diff --git a/src/main/java/caosdb/server/CaosDBServer.java b/src/main/java/caosdb/server/CaosDBServer.java index 9ec790b2322ea8ddc2fa227d633a12cda5ae3a6f..07a57c5918405f7ef5f8fd6949d9dfd32bd08434 100644 --- a/src/main/java/caosdb/server/CaosDBServer.java +++ b/src/main/java/caosdb/server/CaosDBServer.java @@ -27,6 +27,7 @@ import caosdb.server.accessControl.OneTimeTokenRealm; import caosdb.server.accessControl.Principal; import caosdb.server.accessControl.SessionToken; import caosdb.server.accessControl.SessionTokenRealm; +import caosdb.server.converter.misc.HttpStatusConverter; import caosdb.server.converter.misc.MultipartContainerConverter; import caosdb.server.converter.xml.EntityXMLConverterHelper; import caosdb.server.database.BackendTransaction; @@ -100,6 +101,7 @@ import org.restlet.data.Reference; import org.restlet.data.ServerInfo; import org.restlet.data.Status; import org.restlet.engine.Engine; +import org.restlet.engine.converter.DefaultConverter; import org.restlet.routing.Route; import org.restlet.routing.Router; import org.restlet.routing.Template; @@ -345,8 +347,13 @@ public class CaosDBServer extends Application { init.release(); - Engine.getInstance().getRegisteredConverters().add(new EntityXMLConverterHelper()); + Engine.getInstance().getRegisteredConverters().clear(); + Engine.getInstance().getRegisteredConverters().add(new DefaultConverter()); + // add XML Converters + EntityXMLConverterHelper xmlConverter = new EntityXMLConverterHelper(); + Engine.getInstance().getRegisteredConverters().add(xmlConverter); Engine.getInstance().getRegisteredConverters().add(new MultipartContainerConverter()); + Engine.getInstance().getRegisteredConverters().add(new HttpStatusConverter(xmlConverter)); if (INSECURE) { runHTTPServer(port_http, initialConnections, maxTotalConnections); diff --git a/src/main/java/caosdb/server/converter/misc/CaosDBStatusService.java b/src/main/java/caosdb/server/converter/misc/CaosDBStatusService.java new file mode 100644 index 0000000000000000000000000000000000000000..f0acd7a16c38fe0281ebb40335987b31c9117934 --- /dev/null +++ b/src/main/java/caosdb/server/converter/misc/CaosDBStatusService.java @@ -0,0 +1,7 @@ +package caosdb.server.converter.misc; + +import org.restlet.service.StatusService; + +public class CaosDBStatusService extends StatusService { + +} diff --git a/src/main/java/caosdb/server/converter/misc/HttpStatusConverter.java b/src/main/java/caosdb/server/converter/misc/HttpStatusConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..926a61e1ea54645584290800850b488ffbe8c829 --- /dev/null +++ b/src/main/java/caosdb/server/converter/misc/HttpStatusConverter.java @@ -0,0 +1,96 @@ +package caosdb.server.converter.misc; + +import java.io.IOException; +import java.util.List; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; +import org.restlet.data.Status; +import org.restlet.engine.application.StatusInfo; +import org.restlet.engine.converter.ConverterHelper; +import org.restlet.engine.resource.VariantInfo; +import org.restlet.representation.Representation; +import org.restlet.representation.Variant; +import org.restlet.resource.Resource; +import caosdb.server.entity.Message; +import caosdb.server.entity.container.TransactionContainer; +import caosdb.server.utils.ServerMessages; + +public class HttpStatusConverter extends ConverterHelper { + + private AbstractContainerHelper containerConverter; + private TransactionContainer dummyContainer; + + public HttpStatusConverter(AbstractContainerHelper converter) { + this.containerConverter = converter; + this.dummyContainer = new TransactionContainer(); + } + + @Override + public List<Class<?>> getObjectClasses(Variant source) { + // the server does not need this. + return null; + } + + @Override + public List<VariantInfo> getVariants(Class<?> source) throws IOException { + if (isCompatible(source)) { + return containerConverter.getVariants(TransactionContainer.class); + } + return null; + } + + private boolean isCompatible(Class<?> source) { + return source != null && source.isAssignableFrom(StatusInfo.class); + } + + @Override + public float score(Object source, Variant target, Resource resource) { + return containerConverter.score(dummyContainer, target, resource); + } + + @Override + public <T> float score(Representation source, Class<T> target, Resource resource) { + // no implementation for this direction of the conversion + return -1.0F; + } + + @Override + public <T> T toObject(Representation source, Class<T> target, Resource resource) + throws IOException { + // the server does not need this. + return null; + } + + @Override + public Representation toRepresentation(Object source, Variant target, Resource resource) + throws IOException { + Representation result = null; + + if (source != null && StatusInfo.class.isAssignableFrom(source.getClass())) { + StatusInfo status = (StatusInfo) source; + result = toJdomRepresentation(status, target, resource); + } + + return result; + } + + private Representation toJdomRepresentation(StatusInfo status, Variant target, Resource resource) + throws IOException { + Subject owner = SecurityUtils.getSubject(); + Long timestamp = null; + String requestId = null; + if (resource != null) { + timestamp = resource.getRequest().getDate().getTime(); + requestId = resource.getRequestAttributes().get("SRID").toString(); + } + + TransactionContainer t = new TransactionContainer(owner, timestamp, requestId); + if (status.getCode() == 500) { + t.addMessage(ServerMessages.UNKNOWN_ERROR(requestId)); + } else { + t.addMessage(new Message((Status.valueOf(status.getCode()).isError() ? "Error" : "Info"), + status.getCode(), status.getReasonPhrase(), status.getDescription())); + } + return containerConverter.toRepresentation(t, target, resource); + } +} diff --git a/src/main/java/caosdb/server/converter/xml/MessageConverter.java b/src/main/java/caosdb/server/converter/xml/MessageConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..46dda340312259c6dbb547448efd5a6986064218 --- /dev/null +++ b/src/main/java/caosdb/server/converter/xml/MessageConverter.java @@ -0,0 +1,70 @@ +package caosdb.server.converter.xml; + +import caosdb.server.converter.misc.AbstractContainerHelper; +import caosdb.server.entity.Message; +import caosdb.server.entity.container.TransactionContainer; +import java.io.IOException; +import java.util.List; +import org.restlet.engine.converter.ConverterHelper; +import org.restlet.engine.resource.VariantInfo; +import org.restlet.representation.Representation; +import org.restlet.representation.Variant; +import org.restlet.resource.Resource; + +public class MessageConverter extends ConverterHelper { + + private final AbstractContainerHelper containerConverter; + + public MessageConverter(AbstractContainerHelper containerConverter) { + this.containerConverter = containerConverter; + } + + @Override + public List<Class<?>> getObjectClasses(Variant source) { + // no conversion to message needed. + return null; + } + + @Override + public List<VariantInfo> getVariants(Class<?> source) throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public float score(Object source, Variant target, Resource resource) { + if (source instanceof Message) { + return getContainerConverter().score(wrapp(source), target, resource); + } + // TODO Auto-generated method stub + return -1.0F; + } + + private TransactionContainer wrapp(Object source) { + return null; + } + + @Override + public <T> float score(Representation source, Class<T> target, Resource resource) { + // TODO Auto-generated method stub + return -1.0F; + } + + @Override + public <T> T toObject(Representation source, Class<T> target, Resource resource) + throws IOException { + // no implementation needed. + return null; + } + + @Override + public Representation toRepresentation(Object source, Variant target, Resource resource) + throws IOException { + // TODO Auto-generated method stub + return null; + } + + public AbstractContainerHelper getContainerConverter() { + return containerConverter; + } +} diff --git a/src/main/java/caosdb/server/entity/Message.java b/src/main/java/caosdb/server/entity/Message.java index 0ffedb4316fe372e09f3b69ca5824a72f98accaf..b57d6166df3df7a8913605a0af105907bd7be3f6 100644 --- a/src/main/java/caosdb/server/entity/Message.java +++ b/src/main/java/caosdb/server/entity/Message.java @@ -22,8 +22,9 @@ */ package caosdb.server.entity; -import caosdb.server.entity.xml.ToElementable; import org.jdom2.Element; +import org.restlet.data.Status; +import caosdb.server.entity.xml.ToElementable; public class Message extends Exception implements Comparable<Message>, ToElementable { @@ -39,6 +40,10 @@ public class Message extends Exception implements Comparable<Message>, ToElement Error, Info }; + + public Message(Status status) { + this(status.isError()? "Error" : "Info", status.getCode(), status.getReasonPhrase(), status.getDescription()); + } @Override public int hashCode() { diff --git a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java index c947bf81ea9631c9816987475e95cf9ab1b6517b..7e2a483af1f87a33ee7ffc2f82a6f1d5a806c377 100644 --- a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java +++ b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java @@ -23,11 +23,18 @@ */ package caosdb.server.resource; -import caosdb.server.utils.WebinterfaceUtils; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.restlet.data.MediaType; +import org.restlet.data.Status; +import org.restlet.engine.application.StatusInfo; +import org.restlet.representation.Representation; +import org.restlet.representation.Variant; import org.restlet.resource.ServerResource; +import caosdb.server.utils.WebinterfaceUtils; /** * Base class for all CaosDB Server Resources. @@ -86,4 +93,38 @@ public abstract class AbstractCaosDBServerResource extends ServerResource { public final String getSRID() { return getRequest().getAttributes().get("SRID").toString(); } + + /* + * Stolen from Restlet and adapted to our needs. + */ + @Override + protected void doCatch(Throwable throwable) { + Level level = Level.INFO; + Status status = getStatusService().toStatus(throwable, this); + + if (status.isServerError()) { + level = Level.SEVERE; + } else if (status.isConnectorError()) { + level = Level.INFO; + } else if (status.isClientError()) { + level = Level.FINE; + } + + getLogger().log(level, "Exception or error caught in server resource", + throwable); + + if (getResponse() != null) { + getResponse().setStatus(status); + + List<Variant> variants = getVariants(getMethod()); + Variant preferredVariant = getPreferredVariant(variants); + try { + Representation errorEntity; + errorEntity = toRepresentation(new StatusInfo(status), preferredVariant); + getResponse().setEntity(errorEntity); + } catch (IOException e) { + getLogger().log(Level.SEVERE, "Exception during serialization of another error.", e); + } + } + } }