You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2017/11/28 13:47:44 UTC
[isis] 02/02: ISIS-1768: supports either xml or json formats,
improved representations, and simplified implementation
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 43f84745b3c3890259c413e64c2eca511b8dac9d
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Nov 28 13:15:36 2017 +0000
ISIS-1768: supports either xml or json formats, improved representations, and simplified implementation
---
.../server/ExceptionMapperAbstract.java | 65 -----------
.../server/ExceptionPojoWithDetail.java | 64 -----------
.../server/ObjectNotFoundExceptionMapper.java | 71 ------------
.../server/RestfulObjectsApplication.java | 9 +-
.../RestfulObjectsApplicationExceptionMapper.java | 101 -----------------
.../server/mappers/ExceptionMapperAbstract.java | 120 +++++++++++++++++++++
.../mappers/ExceptionMapperForObjectNotFound.java | 35 ++++++
...xceptionMapperForRestfulObjectsApplication.java | 36 +++++++
.../ExceptionMapperForRuntimeException.java} | 33 ++----
.../entity/ExceptionDetail.java} | 72 ++++++-------
.../server/{ => mappers/entity}/ExceptionPojo.java | 51 ++++-----
.../server/mappers/entity/package-info.java | 28 +++++
.../resources/DomainObjectResourceServerside.java | 12 +--
...stfulObjectsApplicationExceptionMapperTest.java | 29 ++---
.../java/domainapp/dom/impl/HelloWorldObjects.java | 27 +++++
15 files changed, 341 insertions(+), 412 deletions(-)
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionMapperAbstract.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionMapperAbstract.java
deleted file mode 100644
index ad38101..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionMapperAbstract.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.isis.viewer.restfulobjects.server;
-
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
-
-public abstract class ExceptionMapperAbstract<T extends Throwable> implements ExceptionMapper<T> {
-
- @Context
- protected HttpHeaders httpHeaders;
-
- protected void setContentTypeOn(final ResponseBuilder builder) {
- final boolean xml = isXmlButNotHtml();
- if(!xml) {
- builder.type(RestfulMediaType.APPLICATION_JSON_ERROR);
- } else {
- builder.type(RestfulMediaType.APPLICATION_XML_ERROR);
- }
- }
-
- protected boolean isHtml() {
- for (final MediaType acceptableMediaType : httpHeaders.getAcceptableMediaTypes()) {
- if(acceptableMediaType.getType().equals("text") && acceptableMediaType.getSubtype().equals("html")) {
- return true;
- }
- }
- return false;
- }
-
- protected boolean isXmlButNotHtml() {
- if (isHtml()) {
- return false;
- }
- for (final MediaType acceptableMediaType : httpHeaders.getAcceptableMediaTypes()) {
- if(acceptableMediaType.getSubtype().equals("xml")) {
- return true;
- }
- }
- return false;
- }
-
-
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojoWithDetail.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojoWithDetail.java
deleted file mode 100644
index 18af126..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojoWithDetail.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.isis.viewer.restfulobjects.server;
-
-import java.util.List;
-
-import com.google.common.collect.Lists;
-
-class ExceptionPojoWithDetail extends ExceptionPojo {
-
- private static String format(final StackTraceElement stackTraceElement) {
- return stackTraceElement.toString();
- }
-
- private final String className;
-
- private final List<String> stackTrace = Lists.newArrayList();
- private ExceptionPojoWithDetail causedBy;
-
- public ExceptionPojoWithDetail(final Throwable ex) {
- super(ex);
- this.className = ex.getClass().getName();
- final StackTraceElement[] stackTraceElements = ex.getStackTrace();
- for (final StackTraceElement stackTraceElement : stackTraceElements) {
- this.stackTrace.add(format(stackTraceElement));
- }
- final Throwable cause = ex.getCause();
- if (cause != null && cause != ex) {
- this.causedBy = new ExceptionPojoWithDetail(cause);
- }
- }
-
- @SuppressWarnings("unused")
- public String getClassName() {
- return className;
- }
-
- @SuppressWarnings("unused")
- public List<String> getStackTrace() {
- return stackTrace;
- }
-
- @SuppressWarnings("unused")
- public ExceptionPojoWithDetail getCausedBy() {
- return causedBy;
- }
-
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ObjectNotFoundExceptionMapper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ObjectNotFoundExceptionMapper.java
deleted file mode 100644
index 4b1e154..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ObjectNotFoundExceptionMapper.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.isis.viewer.restfulobjects.server;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse.HttpStatusCode;
-import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
-
-@Provider
-public class ObjectNotFoundExceptionMapper extends ExceptionMapperAbstract<ObjectNotFoundException> {
-
- @Override
- public Response toResponse(final ObjectNotFoundException ex) {
-
-
- final HttpStatusCode statusCode = HttpStatusCode.NOT_FOUND;
- final ResponseBuilder builder =
- Response.status(statusCode.getJaxrsStatusType());
-
- final String message = ex.getMessage();
- if (message != null) {
- builder.header(RestfulResponse.Header.WARNING.getName(), RestfulResponse.Header.WARNING.render(message));
- }
-
- setContentTypeOn(builder);
-
- String body = toBody(ex);
-
- if(body != null) {
- builder.entity(body);
- }
-
- return builder.build();
- }
-
- protected String toBody(final ObjectNotFoundException ex) {
- final boolean xml = isXmlButNotHtml();
- if (!xml) {
- String body;
- try {
- body = JsonMapper.instance().write(new ExceptionPojo(ex));
- } catch (final Exception e) {
- // fallback
- body = "{ \"message\": \"" + ex.getMessage() + "\" }";
- }
- return body;
- }
- return null;
- }
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
index fac1c27..7c33c52 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
@@ -20,6 +20,9 @@ package org.apache.isis.viewer.restfulobjects.server;
import org.apache.isis.viewer.restfulobjects.rendering.service.acceptheader.AcceptHeaderServiceForRest;
import org.apache.isis.viewer.restfulobjects.server.conneg.RestfulObjectsJaxbWriterForXml;
+import org.apache.isis.viewer.restfulobjects.server.mappers.ExceptionMapperForObjectNotFound;
+import org.apache.isis.viewer.restfulobjects.server.mappers.ExceptionMapperForRestfulObjectsApplication;
+import org.apache.isis.viewer.restfulobjects.server.mappers.ExceptionMapperForRuntimeException;
import org.apache.isis.viewer.restfulobjects.server.resources.DomainObjectResourceServerside;
import org.apache.isis.viewer.restfulobjects.server.resources.DomainServiceResourceServerside;
import org.apache.isis.viewer.restfulobjects.server.resources.DomainTypeResourceServerside;
@@ -47,9 +50,9 @@ public class RestfulObjectsApplication extends AbstractJaxRsApplication {
final RestfulObjectsJaxbWriterForXml roWriter = new RestfulObjectsJaxbWriterForXml();
addSingleton(roWriter);
- addSingleton(new RestfulObjectsApplicationExceptionMapper());
- addSingleton(new RuntimeExceptionMapper());
- addSingleton(new ObjectNotFoundExceptionMapper());
+ addSingleton(new ExceptionMapperForRestfulObjectsApplication());
+ addSingleton(new ExceptionMapperForRuntimeException());
+ addSingleton(new ExceptionMapperForObjectNotFound());
addSingleton(new AcceptHeaderServiceForRest.RequestFilter());
addSingleton(new AcceptHeaderServiceForRest.ResponseFilter());
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
deleted file mode 100644
index 210f8aa..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.isis.viewer.restfulobjects.server;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.isis.core.commons.exceptions.ExceptionUtils;
-import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
-import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
-import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
-
-//@Path("/") // FIXME: workaround for TomEE ... but breaks the RestEasy TCK tests so commented out:-(
-@Provider
-public class RestfulObjectsApplicationExceptionMapper extends ExceptionMapperAbstract<RestfulObjectsApplicationException> {
-
- @Override
- public Response toResponse(final RestfulObjectsApplicationException ex) {
- final ResponseBuilder builder = Response.status(ex.getHttpStatusCode().getJaxrsStatusType());
-
- final String message = ex.getMessage();
- if (message != null) {
- builder.header(RestfulResponse.Header.WARNING.getName(), RestfulResponse.Header.WARNING.render(message));
- }
-
- setContentTypeOn(builder);
-
- final boolean xml = isXmlButNotHtml();
- String body = null;
- if(!xml) {
- final JsonRepresentation bodyRepr = ex.getBody();
- if (bodyRepr != null) {
- body = bodyRepr.toString();
- }
- }
- if (body == null) {
- body = toBody(ex);
- }
-
- if(body != null) {
- builder.entity(body);
- }
-
- return builder.build();
- }
-
- protected String toBody(final RestfulObjectsApplicationException ex) {
- if(ex.getHttpStatusCode() == RestfulResponse.HttpStatusCode.NOT_FOUND) {
- final ExceptionPojo exceptionPojo = new ExceptionPojo(ex);
- try {
- return JsonMapper.instance().write(exceptionPojo);
- } catch (final Exception e) {
- // fallback
- return null;
- }
- }
-
- final boolean xml = isXmlButNotHtml();
- final ExceptionPojoWithDetail exceptionPojo = new ExceptionPojoWithDetail(ex);
- if (!xml) {
- try {
- return JsonMapper.instance().write(exceptionPojo);
- } catch (final Exception e) {
- // fallback
- return "{ \"exception\": \"" + ExceptionUtils.getFullStackTrace(ex) + "\" }";
- }
- } else {
- final StringBuilder buf = new StringBuilder();
- buf.append("<exception>\n");
- buf.append(" <httpStatusCode>").append(exceptionPojo.getHttpStatusCode())
- .append("</httpStatusCode>/n");
- buf.append(" <message>").append(exceptionPojo.getMessage()).append("</message>/n");
- buf.append(" <stackTrace>/n");
- for (String line : exceptionPojo.getStackTrace()) {
- buf.append(" <stackTraceElement>").append(line).append(" </stackTraceElement>/n");
- }
- buf.append(" </stackTrace>/n");
- buf.append("</exception>");
-
- return buf.toString();
- }
- }
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperAbstract.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperAbstract.java
new file mode 100644
index 0000000..0977835
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperAbstract.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.restfulobjects.server.mappers;
+
+import java.util.List;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+
+import org.jboss.resteasy.spi.Failure;
+
+import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
+import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
+import org.apache.isis.viewer.restfulobjects.rendering.HasHttpStatusCode;
+import org.apache.isis.viewer.restfulobjects.server.mappers.entity.ExceptionDetail;
+import org.apache.isis.viewer.restfulobjects.server.mappers.entity.ExceptionPojo;
+import org.apache.isis.viewer.restfulobjects.server.resources.serialization.SerializationStrategy;
+
+public abstract class ExceptionMapperAbstract<T extends Throwable> implements ExceptionMapper<T> {
+
+ @Context
+ protected HttpHeaders httpHeaders;
+
+ Response buildResponse(final T ex) {
+ final RestfulResponse.HttpStatusCode httpStatusCode = determineStatusCode(ex);
+ final String message = messageFor(ex);
+
+ final ExceptionPojo exceptionPojo =
+ new ExceptionPojo(
+ httpStatusCode.getStatusCode(), message,
+ detailIfRequired(httpStatusCode, ex)
+ );
+
+ return buildResponse(httpStatusCode, exceptionPojo);
+ }
+
+ private RestfulResponse.HttpStatusCode determineStatusCode(final T ex) {
+ final List<Throwable> chain = Throwables.getCausalChain(ex);
+
+ RestfulResponse.HttpStatusCode statusCode;
+ if(ex instanceof Failure) {
+ Failure failure = (Failure) ex;
+ statusCode = RestfulResponse.HttpStatusCode.statusFor(failure.getErrorCode());
+ } else if(!FluentIterable.from(chain).filter(RecoverableException.class).isEmpty()) {
+ statusCode = RestfulResponse.HttpStatusCode.OK;
+ } else if(ex instanceof HasHttpStatusCode) {
+ HasHttpStatusCode hasHttpStatusCode = (HasHttpStatusCode) ex;
+ statusCode = hasHttpStatusCode.getHttpStatusCode();
+ } else {
+ statusCode = RestfulResponse.HttpStatusCode.INTERNAL_SERVER_ERROR;
+ }
+ return statusCode;
+ }
+
+ private static String messageFor(final Throwable ex) {
+ final List<Throwable> chain = Throwables.getCausalChain(ex);
+ final Optional<RecoverableException> recoverableIfAny =
+ FluentIterable.from(chain).filter(RecoverableException.class).first();
+ return (recoverableIfAny.isPresent() ? recoverableIfAny.get() : ex).getMessage();
+ }
+
+ private ExceptionDetail detailIfRequired(
+ final RestfulResponse.HttpStatusCode httpStatusCode,
+ final Throwable ex) {
+ return httpStatusCode == RestfulResponse.HttpStatusCode.NOT_FOUND ||
+ httpStatusCode == RestfulResponse.HttpStatusCode.OK
+ ? null
+ : new ExceptionDetail(ex);
+ }
+
+ private Response buildResponse(
+ final RestfulResponse.HttpStatusCode httpStatusCode,
+ final ExceptionPojo exceptionPojo) {
+ final ResponseBuilder builder = Response.status(httpStatusCode.getJaxrsStatusType());
+
+ final List<MediaType> acceptableMediaTypes = httpHeaders.getAcceptableMediaTypes();
+ final SerializationStrategy serializationStrategy =
+ acceptableMediaTypes.contains(MediaType.APPLICATION_XML_TYPE) ||
+ acceptableMediaTypes.contains(RepresentationType.OBJECT_LAYOUT.getXmlMediaType())
+ ? SerializationStrategy.XML
+ : SerializationStrategy.JSON;
+
+ final String message = exceptionPojo.getMessage();
+ if (message != null) {
+ builder.header(RestfulResponse.Header.WARNING.getName(), RestfulResponse.Header.WARNING.render(message));
+ }
+
+ builder.type(serializationStrategy.type(RepresentationType.ERROR));
+ builder.entity(serializationStrategy.entity(exceptionPojo));
+
+ return builder.build();
+ }
+
+
+}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForObjectNotFound.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForObjectNotFound.java
new file mode 100644
index 0000000..998d05e
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForObjectNotFound.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.restfulobjects.server.mappers;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
+
+@Provider
+public class ExceptionMapperForObjectNotFound extends ExceptionMapperAbstract<ObjectNotFoundException> {
+
+ @Override
+ public Response toResponse(final ObjectNotFoundException ex) {
+
+ return buildResponse(ex);
+ }
+
+}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRestfulObjectsApplication.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRestfulObjectsApplication.java
new file mode 100644
index 0000000..da04ffe
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRestfulObjectsApplication.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.restfulobjects.server.mappers;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
+
+//@Path("/") // FIXME: workaround for TomEE ... but breaks the RestEasy TCK tests so commented out:-(
+@Provider
+public class ExceptionMapperForRestfulObjectsApplication extends ExceptionMapperAbstract<RestfulObjectsApplicationException> {
+
+ @Override
+ public Response toResponse(final RestfulObjectsApplicationException ex) {
+ return buildResponse(ex);
+ }
+
+
+}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRuntimeException.java
similarity index 57%
rename from core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
rename to core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRuntimeException.java
index bdf3866..2596c65 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRuntimeException.java
@@ -16,63 +16,42 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.restfulobjects.server;
+package org.apache.isis.viewer.restfulobjects.server.mappers;
import java.util.List;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import com.google.common.base.Throwables;
-import org.jboss.resteasy.spi.Failure;
-
-import org.apache.isis.core.commons.exceptions.ExceptionUtils;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
-import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse.HttpStatusCode;
-import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
@Provider
-public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
+public class ExceptionMapperForRuntimeException extends ExceptionMapperAbstract<RuntimeException> {
@Override
public Response toResponse(final RuntimeException ex) {
+ // since already rendered...
final IsisTransaction currentTransaction = getIsisSessionFactory().getCurrentSession()
.getPersistenceSession().getTransactionManager().getCurrentTransaction();
final Throwable rootCause = Throwables.getRootCause(ex);
final List<Throwable> causalChain = Throwables.getCausalChain(ex);
for (Throwable throwable : causalChain) {
-
if(throwable == rootCause) {
currentTransaction.clearAbortCause();
}
}
- HttpStatusCode statusCode = HttpStatusCode.INTERNAL_SERVER_ERROR;
- if(ex instanceof Failure) {
- Failure failure = (Failure) ex;
- statusCode = HttpStatusCode.statusFor(failure.getErrorCode());
- }
- final ResponseBuilder builder = Response.status(statusCode.getJaxrsStatusType()).type(RestfulMediaType.APPLICATION_JSON_ERROR).entity(jsonFor(ex));
- return builder.build();
- }
- static String jsonFor(final Exception ex) {
- try {
- return JsonMapper.instance().write(RuntimeExceptionPojo.create(ex));
- } catch (final Exception e) {
- // fallback
- return "{ \"exception\": \"" + ExceptionUtils.getFullStackTrace(ex) + "\" }";
- }
+ return buildResponse(ex);
}
- IsisSessionFactory getIsisSessionFactory() {
+
+ private IsisSessionFactory getIsisSessionFactory() {
return IsisContext.getSessionFactory();
}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionPojo.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionDetail.java
similarity index 62%
rename from core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionPojo.java
rename to core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionDetail.java
index f86e4d6..d47e2a3 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionPojo.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionDetail.java
@@ -16,30 +16,52 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.restfulobjects.server;
+package org.apache.isis.viewer.restfulobjects.server.mappers.entity;
import java.util.List;
+
import javax.jdo.JDOException;
-import com.google.common.collect.Lists;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
-class RuntimeExceptionPojo {
+import com.google.common.collect.Lists;
- public static RuntimeExceptionPojo create(final Exception ex) {
- return new RuntimeExceptionPojo(ex);
- }
+@XmlRootElement(
+ name = "exceptionDetail"
+)
+@XmlType(
+ name = "exceptionDetail"
+ , propOrder = {
+ "className",
+ "message",
+ "stackTrace",
+ "causedBy"
+ }
+)
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ExceptionDetail {
private static String format(final StackTraceElement stackTraceElement) {
return stackTraceElement.toString();
}
- private final String className;
- private final String message;
- private final List<String> stackTrace = Lists.newArrayList();
- private RuntimeExceptionPojo causedBy;
+ private String className;
+ private String message;
+
+ @XmlElementWrapper()
+ @XmlElement(name="element")
+ private List<String> stackTrace = Lists.newArrayList();
+ private ExceptionDetail causedBy;
- public RuntimeExceptionPojo(final Throwable ex) {
+ public ExceptionDetail() {
+ }
+ public ExceptionDetail(final Throwable ex) {
this.className = ex.getClass().getName();
- this.message = messageFor(ex);
+ this.message = ex.getMessage();
final StackTraceElement[] stackTraceElements = ex.getStackTrace();
for (final StackTraceElement stackTraceElement : stackTraceElements) {
this.stackTrace.add(format(stackTraceElement));
@@ -47,7 +69,7 @@ class RuntimeExceptionPojo {
final Throwable cause = causeOf(ex);
if (cause != null && cause != ex) {
- this.causedBy = new RuntimeExceptionPojo(cause);
+ this.causedBy = new ExceptionDetail(cause);
}
}
@@ -62,28 +84,4 @@ class RuntimeExceptionPojo {
}
}
- private static String messageFor(final Throwable ex) {
- final String message = ex.getMessage();
- return message != null ? message : ex.getClass().getName();
- }
-
- @SuppressWarnings("unused")
- public String getClassName() {
- return className;
- }
-
- @SuppressWarnings("unused")
- public String getMessage() {
- return message;
- }
-
- @SuppressWarnings("unused")
- public List<String> getStackTrace() {
- return stackTrace;
- }
-
- @SuppressWarnings("unused")
- public RuntimeExceptionPojo getCausedBy() {
- return causedBy;
- }
}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojo.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionPojo.java
similarity index 52%
rename from core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojo.java
rename to core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionPojo.java
index 2e745f0..c0602b2 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojo.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionPojo.java
@@ -16,37 +16,40 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.restfulobjects.server;
-
-import org.apache.isis.viewer.restfulobjects.rendering.HasHttpStatusCode;
-
-class ExceptionPojo {
-
- static int getHttpStatusCodeIfAny(final Throwable ex) {
- if (!(ex instanceof HasHttpStatusCode)) {
- return 0;
- }
- final HasHttpStatusCode hasHttpStatusCode = (HasHttpStatusCode) ex;
- return hasHttpStatusCode.getHttpStatusCode().getStatusCode();
+package org.apache.isis.viewer.restfulobjects.server.mappers.entity;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(
+ name = "exception"
+)
+@XmlType(
+ name = "exception"
+ , propOrder = {
+ "httpStatusCode",
+ "message",
+ "detail",
}
+)
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ExceptionPojo {
+ int httpStatusCode;
+ private String message;
+ private ExceptionDetail detail;
- private final int httpStatusCode;
- private final String message;
+ public ExceptionPojo() { }
- public ExceptionPojo(final Throwable ex) {
- this.httpStatusCode = getHttpStatusCodeIfAny(ex);
- this.message = ex.getMessage();
+ public ExceptionPojo(final int statusCode, final String message, final ExceptionDetail detail) {
+ this.httpStatusCode = statusCode;
+ this.message = message;
+ this.detail = detail;
}
- @SuppressWarnings("unused")
- public int getHttpStatusCode() {
- return httpStatusCode;
- }
-
- @SuppressWarnings("unused")
public String getMessage() {
return message;
}
-
}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/package-info.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/package-info.java
new file mode 100644
index 0000000..f94ac90
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+@javax.xml.bind.annotation.XmlSchema(
+ namespace = "http://isis.apache.org/viewer/restfulobjects/server/mappers/entity",
+ elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
+ xmlns = {
+ @javax.xml.bind.annotation.XmlNs(
+ namespaceURI = "http://isis.apache.org/viewer/restfulobjects/server/mappers/entity", prefix = "ro")
+}
+)
+package org.apache.isis.viewer.restfulobjects.server.mappers.entity;
\ No newline at end of file
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
index 9de98f4..938dfa5 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
@@ -206,20 +206,18 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
init(RepresentationType.OBJECT_LAYOUT, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
- final SerializationStrategy serializationStrategy;
final List<MediaType> acceptableMediaTypes = getResourceContext().getAcceptableMediaTypes();
- if(acceptableMediaTypes.contains(MediaType.APPLICATION_XML_TYPE) || acceptableMediaTypes.contains(RepresentationType.OBJECT_LAYOUT.getXmlMediaType())) {
- serializationStrategy = SerializationStrategy.XML;
- } else {
- serializationStrategy = SerializationStrategy.JSON;
- }
+ final SerializationStrategy serializationStrategy =
+ acceptableMediaTypes.contains(MediaType.APPLICATION_XML_TYPE) ||
+ acceptableMediaTypes.contains(RepresentationType.OBJECT_LAYOUT.getXmlMediaType())
+ ? SerializationStrategy.XML
+ : SerializationStrategy.JSON;
final ObjectSpecification objectSpec = getSpecificationLoader().lookupBySpecId(ObjectSpecId.of(domainType));
final GridFacet gridFacet = objectSpec.getFacet(GridFacet.class);
final Response.ResponseBuilder builder;
if(gridFacet == null) {
builder = Responses.ofNotFound();
- return builder.build();
} else {
Grid grid = gridFacet.getGrid();
addLinks(domainType, instanceId, grid);
diff --git a/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapperTest.java b/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/mappers/RestfulObjectsApplicationExceptionMapperTest.java
similarity index 82%
rename from core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapperTest.java
rename to core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/mappers/RestfulObjectsApplicationExceptionMapperTest.java
index 5cc00bf..7c5ad83 100644
--- a/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapperTest.java
+++ b/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/mappers/RestfulObjectsApplicationExceptionMapperTest.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.restfulobjects.server;
+package org.apache.isis.viewer.restfulobjects.server.mappers;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
@@ -39,7 +39,7 @@ import static org.junit.Assert.assertThat;
public class RestfulObjectsApplicationExceptionMapperTest {
- private RestfulObjectsApplicationExceptionMapper exceptionMapper;
+ private ExceptionMapperForRestfulObjectsApplication exceptionMapper;
@Rule
public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
@@ -49,7 +49,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
@Before
public void setUp() throws Exception {
- exceptionMapper = new RestfulObjectsApplicationExceptionMapper();
+ exceptionMapper = new ExceptionMapperForRestfulObjectsApplication();
exceptionMapper.httpHeaders = mockHttpHeaders;
}
@@ -71,7 +71,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
// and then
final String entity = (String) response.getEntity();
- assertThat(entity, is(nullValue()));
+ assertThat(entity, is(not(nullValue())));
}
@Test
@@ -89,7 +89,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
// and then
final String entity = (String) response.getEntity();
- assertThat(entity, is(nullValue()));
+ assertThat(entity, is(not(nullValue())));
}
@Test
@@ -108,7 +108,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
// then
assertThat((String) response.getMetadata().get("Warning").get(0), is("199 RestfulObjects foobar"));
- assertThat(jsonRepr.getString("message"), is("barfoo"));
+ assertThat(jsonRepr.getString("message"), is("foobar"));
final JsonRepresentation causedByRepr = jsonRepr.getRepresentation("causedBy");
assertThat(causedByRepr, is(nullValue()));
}
@@ -118,9 +118,9 @@ public class RestfulObjectsApplicationExceptionMapperTest {
// given
context.allowing(mockHttpHeaders);
- final Exception cause = new Exception("bozfoz");
- final Exception exception = new Exception("barfoo", cause);
- final RestfulObjectsApplicationException ex = RestfulObjectsApplicationException.createWithCauseAndMessage(HttpStatusCode.BAD_REQUEST, exception, "foobar");
+ final Exception rootCause = new Exception("bozfoz");
+ final Exception cause = new Exception("barfoo", rootCause);
+ final RestfulObjectsApplicationException ex = RestfulObjectsApplicationException.createWithCauseAndMessage(HttpStatusCode.BAD_REQUEST, cause, "foobar");
// when
final Response response = exceptionMapper.toResponse(ex);
@@ -130,10 +130,13 @@ public class RestfulObjectsApplicationExceptionMapperTest {
// then
assertThat((String) response.getMetadata().get("Warning").get(0), is("199 RestfulObjects foobar"));
- assertThat(jsonRepr.getString("message"), is("barfoo"));
- final JsonRepresentation causedByRepr = jsonRepr.getRepresentation("causedBy");
- assertThat(causedByRepr, is(not(nullValue())));
- assertThat(causedByRepr.getString("message"), is(cause.getMessage()));
+ assertThat(jsonRepr.getString("message"), is("foobar"));
+ final JsonRepresentation detail = jsonRepr.getRepresentation("detail");
+ assertThat(detail, is(not(nullValue())));
+ assertThat(detail.getString("message"), is("foobar"));
+ final JsonRepresentation causedBy = detail.getRepresentation("causedBy");
+ assertThat(causedBy, is(not(nullValue())));
+ assertThat(causedBy.getString("message"), is(cause.getMessage()));
}
}
diff --git a/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java b/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java
index 242cf7e..84f89c7 100644
--- a/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java
+++ b/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java
@@ -22,6 +22,9 @@ import java.util.List;
import org.datanucleus.query.typesafe.TypesafeQuery;
+import org.apache.isis.applib.ApplicationException;
+import org.apache.isis.applib.NonRecoverableException;
+import org.apache.isis.applib.RecoverableException;
import org.apache.isis.applib.annotation.Action;
import org.apache.isis.applib.annotation.DomainService;
import org.apache.isis.applib.annotation.MemberOrder;
@@ -60,6 +63,30 @@ public class HelloWorldObjects {
.executeList();
}
+ @Action(semantics = SemanticsOf.SAFE)
+ @MemberOrder(sequence = "2.1")
+ public void throwRuntimeException() {
+ throw new RuntimeException("all gone wrong - a RuntimeException!");
+ }
+
+ @Action(semantics = SemanticsOf.SAFE)
+ @MemberOrder(sequence = "2.2")
+ public void throwRecoverableException() {
+ throw new RecoverableException("all gone wrong - a RecoverableException!");
+ }
+
+ @Action(semantics = SemanticsOf.SAFE)
+ @MemberOrder(sequence = "2.3")
+ public void throwNonRecoverableException() {
+ throw new NonRecoverableException("all gone wrong - a NonRecoverableException!");
+ }
+
+ @Action(semantics = SemanticsOf.SAFE)
+ @MemberOrder(sequence = "2.4")
+ public void throwApplicableException() {
+ throw new ApplicationException("all gone wrong - an ApplicationException!");
+ }
+
@Action(semantics = SemanticsOf.SAFE, restrictTo = RestrictTo.PROTOTYPING)
@MemberOrder(sequence = "3")
public List<HelloWorldObject> listAll() {
--
To stop receiving notification emails like this one, please contact
"commits@isis.apache.org" <co...@isis.apache.org>.