You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by ro...@apache.org on 2009/12/18 00:20:44 UTC
svn commit: r891982 - in /incubator/wink/trunk:
wink-client/src/test/java/org/apache/wink/client/
wink-common/src/main/java/org/apache/wink/common/internal/model/
wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/
wink-com...
Author: rott
Date: Thu Dec 17 23:20:44 2009
New Revision: 891982
URL: http://svn.apache.org/viewvc?rev=891982&view=rev
Log:
support usage of custom providers during AtomEntry->AtomContent->value retrieval when outside the scope of the thread local store of the client-server thread.
Added:
incubator/wink/trunk/wink-client/src/test/java/org/apache/wink/client/ClientAtomTest.java
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntryProvider.java
Modified:
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/model/ModelUtils.java
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntrySyndEntryProvider.java
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/xml/AbstractJAXBProvider.java
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/model/atom/AtomContent.java
incubator/wink/trunk/wink-common/src/main/resources/META-INF/core/wink-providers
Added: incubator/wink/trunk/wink-client/src/test/java/org/apache/wink/client/ClientAtomTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-client/src/test/java/org/apache/wink/client/ClientAtomTest.java?rev=891982&view=auto
==============================================================================
--- incubator/wink/trunk/wink-client/src/test/java/org/apache/wink/client/ClientAtomTest.java (added)
+++ incubator/wink/trunk/wink-client/src/test/java/org/apache/wink/client/ClientAtomTest.java Thu Dec 17 23:20:44 2009
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * 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.wink.client;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.ws.rs.ext.Providers;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.wink.common.internal.providers.entity.xml.JAXBXmlProvider;
+import org.apache.wink.common.model.atom.AtomEntry;
+
+public class ClientAtomTest extends BaseTest {
+
+// @Path("atomresource")
+// private class MyAtomResource {
+// @Path("entry")
+// @GET
+// @Produces("application/atom+xml")
+// public Response getEntry() {
+// MyPojo myPojo = new MyPojo();
+// myPojo.setTitle("wheeee!!!");
+// // wrap POJO (JAXB object) in AtomContent, AtomEntry
+// return Response.status(Status.OK).entity(wrapInAtom(myPojo)).build();
+// }
+//
+// /*
+// * utility method to wrap responses in AtomEntry
+// */
+// private AtomEntry wrapInAtom(Object obj) {
+// AtomContent atomContent = new AtomContent();
+// atomContent.setType(MediaType.APPLICATION_XML);
+// atomContent.setValue(obj);
+// AtomEntry retAtomEntry = new AtomEntry();
+// retAtomEntry.setContent(atomContent);
+// return retAtomEntry;
+// }
+// }
+
+ @XmlRootElement(name = "mypojo", namespace = "http://mypojons/")
+ @XmlType(name = "mypojo", propOrder = {"title"})
+ protected static class MyPojo {
+
+ private String title;
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ }
+
+ private RestClient getRestClient() {
+ return new RestClient(new ClientConfig().applications(new Application() {
+
+ @Override
+ public Set<Object> getSingletons() {
+ return null;
+ }
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ Set<Class<?>> set = new HashSet<Class<?>>();
+ set.add(MyProvider.class);
+ return set;
+ }
+
+ }));
+ }
+
+ @Provider
+ @Consumes( {MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.WILDCARD})
+ @Produces( {MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.WILDCARD})
+ public static class MyProvider extends JAXBXmlProvider {
+
+ @Override
+ public boolean isReadable(Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType) {
+ return true;
+ }
+
+ @Override
+ public Object readFrom(Class<Object> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, String> httpHeaders,
+ InputStream entityStream) throws IOException,
+ WebApplicationException {
+ MyPojo myPojo = (MyPojo)super.readFrom(type, genericType, annotations, mediaType, httpHeaders,
+ entityStream);
+ String oldTitle = myPojo.getTitle();
+ myPojo.setTitle(oldTitle + " -- MyProvider was here.");
+ return myPojo;
+ }
+
+ }
+
+ private final static String responseString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:ns2=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:ns3=\"http://www.w3.org/1999/xhtml\">" +
+ "<content type=\"application/xml\">" +
+ "<ns2:mypojo xmlns:ns2=\"http://mypojons/\">" +
+ "<title xmlns:ns5=\"http://www.w3.org/2005/Atom\" xmlns=\"\">wheeee!!!</title>" +
+ "</ns2:mypojo>" +
+ "</content>" +
+ "</entry>";
+
+ public void testAtomContentRetrieval() {
+ server.setMockResponseCode(200);
+ server.setMockResponseContentType(MediaType.APPLICATION_ATOM_XML);
+ server.setMockResponseContent(responseString);
+ RestClient client = getRestClient();
+ Resource resource = client.resource(serviceURL + "/atomresource/entry");
+
+ // do get with response
+ ClientResponse clientResponse = resource.get();
+ // unwrap the AtomEntry, AtomContent value
+ MyPojo myPojo = (MyPojo)clientResponse.getEntity(AtomEntry.class).getContent().getValue(MyPojo.class);
+
+ // Confirm that the custom MyProvider is used during AtomContent.getValue(MyPojo.class) call.
+ // Custom providers are stored on the client-server transaction's thread local store. This assertion
+ // ensures that the custom providers are held long enough for a client application to use them during
+ // retrieval of the value from the AtomContent object, which occurs in its own thread.
+
+ assertEquals("wheeee!!! -- MyProvider was here.", myPojo.getTitle());
+
+ }
+
+}
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/model/ModelUtils.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/model/ModelUtils.java?rev=891982&r1=891981&r2=891982&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/model/ModelUtils.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/model/ModelUtils.java Thu Dec 17 23:20:44 2009
@@ -22,6 +22,7 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.lang.annotation.Annotation;
@@ -39,6 +40,7 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Providers;
+import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
@@ -60,6 +62,7 @@
import org.apache.wink.common.internal.lifecycle.ScopeLifecycleManager;
import org.apache.wink.common.internal.registry.ProvidersRegistry;
import org.apache.wink.common.internal.registry.metadata.ProviderMetadataCollector;
+import org.apache.wink.common.internal.runtime.AbstractRuntimeContext;
import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
import org.apache.wink.common.internal.utils.UnmodifiableMultivaluedMap;
import org.apache.wink.common.model.atom.AtomContent;
@@ -215,6 +218,7 @@
Annotation[] annotations,
MultivaluedMap<String, String> httpHeaders,
MediaType mediaType) throws IOException {
+
if (list == null || list.isEmpty()) {
return null;
}
@@ -293,10 +297,37 @@
providers = new ProvidersImpl(providersRegistry, runtimeContext);
}
}
+
+ /*
+ * Need to set a temporary RuntimeContextTLS just in case we're already outside of the runtime context.
+ * This may occur when a client app is retrieving the AtomContent value, expecting it to be unmarshalled
+ * automatically, but we are already outside of the client-server thread, and thus no longer have a
+ * RuntimeContextTLS from which to retrieve or inject providers.
+ */
+
+ RuntimeContext tempRuntimeContext = RuntimeContextTLS.getRuntimeContext();
+ if (tempRuntimeContext == null) {
+ final Providers p = providers;
+ RuntimeContextTLS.setRuntimeContext(new AbstractRuntimeContext() {
+ {
+ setAttribute(Providers.class, p);
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return null;
+ }
+ });
+ }
+
MessageBodyReader<T> reader =
providers.getMessageBodyReader(type, type, EMPTY_ARRAY, mediaType);
if (reader == null)
throw new WebApplicationException(Response.Status.UNSUPPORTED_MEDIA_TYPE);
+
T read =
reader.readFrom(type,
type,
@@ -304,6 +335,10 @@
mediaType,
httpHeaders,
new ByteArrayInputStream((byte[])value));
+
+ // Reset RuntimeContext from temporary above. tempRuntimeContext may be null here, which is ok.
+ RuntimeContextTLS.setRuntimeContext(tempRuntimeContext);
+
return read;
}
throw new ClassCastException("Cannot cast " + value.getClass().getName()
Added: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntryProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntryProvider.java?rev=891982&view=auto
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntryProvider.java (added)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntryProvider.java Thu Dec 17 23:20:44 2009
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.wink.common.internal.providers.entity.atom;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.Provider;
+import javax.ws.rs.ext.Providers;
+
+import org.apache.wink.common.internal.providers.entity.xml.JAXBXmlProvider;
+import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
+import org.apache.wink.common.internal.utils.MediaTypeUtils;
+import org.apache.wink.common.model.atom.AtomContent;
+import org.apache.wink.common.model.atom.AtomEntry;
+
+@Provider
+@Consumes( {MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON, MediaTypeUtils.JAVASCRIPT})
+@Produces( {MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON, MediaTypeUtils.JAVASCRIPT})
+public class AtomEntryProvider extends JAXBXmlProvider {
+
+ @Override
+ public boolean isReadable(Class<?> type,
+ Type genericType,
+ Annotation[] annotations,
+ MediaType mediaType) {
+ return type == AtomEntry.class;
+ }
+
+ @Override
+ public Object readFrom(Class<Object> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+ throws IOException, WebApplicationException {
+
+
+ AtomEntry atomEntry = (AtomEntry) super.readFrom(type, genericType, annotations, mediaType, httpHeaders,
+ entityStream);
+
+ /*
+ * The value in the AtomContent object is arbitrary, set by the server. We want to use the
+ * built-in AND client application supplied providers. Because these providers are collected
+ * on the thread local store, and the unmarshalling of the AtomContent value is done lazily
+ * (after the client-server context has expired), we need some way to hold onto the Providers
+ * long enough for the client app to be able to seamlessly get the value off the AtomContent
+ * object. Thus the need to set the *real* providers list on the AtomContent object, so it
+ * can use the list to pass to ModelUtils when it needs to retrieve and unmarshal the AtomContent
+ * value.
+ *
+ * We have to be careful to use the real Providers list instead of the one from the injected
+ * local providers field in this class. The injected object may be a "proxy" to the real
+ * providers, and could cause an infinite loop when ModelUtils.readValue calls back through
+ * the providers.
+ */
+ AtomContent content = atomEntry.getContent();
+ if (content != null) {
+ content.setProviders(RuntimeContextTLS.getRuntimeContext().getAttribute(Providers.class));
+ }
+
+ return atomEntry;
+ }
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType,
+ Annotation[] annotations, MediaType mediaType) {
+ return false; // so JAXBXmlProvider will do the write
+ }
+
+}
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntrySyndEntryProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntrySyndEntryProvider.java?rev=891982&r1=891981&r2=891982&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntrySyndEntryProvider.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/atom/AtomEntrySyndEntryProvider.java Thu Dec 17 23:20:44 2009
@@ -37,7 +37,9 @@
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.Providers;
+import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
import org.apache.wink.common.internal.utils.MediaTypeUtils;
+import org.apache.wink.common.model.atom.AtomContent;
import org.apache.wink.common.model.atom.AtomEntry;
import org.apache.wink.common.model.synd.SyndEntry;
@@ -72,6 +74,27 @@
mediaType,
httpHeaders,
entityStream);
+
+ /*
+ * The value in the AtomContent object is arbitrary, set by the server. We want to use the
+ * built-in AND client application supplied providers. Because these providers are collected
+ * on the thread local store, and the unmarshalling of the AtomContent value is done lazily
+ * (after the client-server context has expired), we need some way to hold onto the Providers
+ * long enough for the client app to be able to seamlessly get the value off the AtomContent
+ * object. Thus the need to set the *real* providers list on the AtomContent object, so it
+ * can use the list to pass to ModelUtils when it needs to retrieve and unmarshal the AtomContent
+ * value.
+ *
+ * We have to be careful to use the real Providers list instead of the one from the injected
+ * local providers field in this class. The injected object may be a "proxy" to the real
+ * providers, and could cause an infinite loop when ModelUtils.readValue calls back through
+ * the providers.
+ */
+ AtomContent content = entry.getContent();
+ if (content != null) {
+ content.setProviders(RuntimeContextTLS.getRuntimeContext().getAttribute(Providers.class));
+ }
+
return entry.toSynd(new SyndEntry());
}
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/xml/AbstractJAXBProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/xml/AbstractJAXBProvider.java?rev=891982&r1=891981&r2=891982&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/xml/AbstractJAXBProvider.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/entity/xml/AbstractJAXBProvider.java Thu Dec 17 23:20:44 2009
@@ -63,7 +63,7 @@
new SoftConcurrentMap<Class<?>, JAXBContext>();
@Context
- private Providers providers;
+ protected Providers providers;
private static final SoftConcurrentMap<Class<?>, Boolean> jaxbIsXMLRootElementCache =
new SoftConcurrentMap<Class<?>, Boolean>();
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/model/atom/AtomContent.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/model/atom/AtomContent.java?rev=891982&r1=891981&r2=891982&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/model/atom/AtomContent.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/model/atom/AtomContent.java Thu Dec 17 23:20:44 2009
@@ -199,6 +199,9 @@
@XmlTransient
private Object savedValue = null;
+ @XmlTransient
+ private Providers providers;
+
public AtomContent() {
}
@@ -224,6 +227,18 @@
value.setValue(getValue(Object.class));
return value;
}
+
+ /**
+ * Sets the Providers on a local field so that the registry of custom and system
+ * providers is available when a client application retrieves the value, expecting
+ * it to be seamlessly unmarshalled or converted to the expected type declared in
+ * getValue(Class).
+ *
+ * Client applications should NOT call this method.
+ */
+ public void setProviders(Providers _providers) {
+ providers = _providers;
+ }
/**
* Gets the value of type.
@@ -339,7 +354,7 @@
try {
return getValue(cls,
cls,
- null,
+ providers,
ModelUtils.EMPTY_ARRAY,
ModelUtils.EMPTY_STRING_MAP,
ModelUtils.determineMediaType(type));
Modified: incubator/wink/trunk/wink-common/src/main/resources/META-INF/core/wink-providers
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/resources/META-INF/core/wink-providers?rev=891982&r1=891981&r2=891982&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/resources/META-INF/core/wink-providers (original)
+++ incubator/wink/trunk/wink-common/src/main/resources/META-INF/core/wink-providers Thu Dec 17 23:20:44 2009
@@ -38,12 +38,12 @@
org.apache.wink.common.internal.providers.entity.SourceProvider$DOMSourceProvider
org.apache.wink.common.internal.providers.entity.StreamingOutputProvider
-
# JAXB Providers
org.apache.wink.common.internal.providers.entity.xml.JAXBElementXmlProvider
org.apache.wink.common.internal.providers.entity.xml.JAXBXmlProvider
# Atom
+org.apache.wink.common.internal.providers.entity.atom.AtomEntryProvider
org.apache.wink.common.internal.providers.entity.atom.AtomFeedSyndFeedProvider
org.apache.wink.common.internal.providers.entity.atom.AtomEntrySyndEntryProvider