package org.jboss.resteasy.plugins.providers.jackson; import java.io.IOException; import java.io.OutputStreamWriter; import javax.ws.rs.ConstrainedTo; import javax.ws.rs.RuntimeType; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.Providers; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import org.codehaus.jackson.map.ObjectMapper; import org.jboss.resteasy.core.MediaTypeMap; import org.jboss.resteasy.resteasy_jaxrs.i18n.*; /** * <p> * JSONP is an alternative to normal AJAX requests. Instead of using a XMLHttpRequest a script tag is added to the DOM. * The browser will call the corresponding URL and download the JavaScript. The server creates a response which looks like a * method call. The parameter is the body of the request. The name of the method to call is normally passed as query parameter. * The method has to be present in the current JavaScript environment. * </p> * <p> * Jackson JSON processor can produce such an response. This interceptor checks if the media type is a JavaScript one if there is a query * parameter with the method name. The default name of this query parameter is "callback". So this interceptor is compatible with * <a href="http://api.jquery.com/jQuery.ajax/">jQuery</a>. * </p> * * @author <a href="mailto:holger.morch@nokia.com">Holger Morch</a> * @version $Revision: 1 $ * @deprecated Use resteasy-jackson2-provider */ @Provider @ConstrainedTo(RuntimeType.SERVER) @Deprecated public class JacksonJsonpInterceptor implements WriterInterceptor{ /** * "text/javascript" media type. Default media type of script tags. */ public static final MediaType TEXT_JAVASCRIPT_MEDIA_TYPE = new MediaType("text", "javascript"); /** * "application/javascript" media type. */ public static final MediaType APPLICATION_JAVASCRIPT_MEDIA_TYPE = new MediaType("application", "javascript"); /** * "text/json" media type. */ public static final MediaType TEXT_JSON_TYPE = new MediaType("text", "json"); /** * "application/*+json" media type. */ public static final MediaType APPLICATION_PLUS_JSON_TYPE = new MediaType("application", "*+json"); /** * Default name of the query parameter with the method name. */ public static final String DEFAULT_CALLBACK_QUERY_PARAMETER = "callback"; /** * If response media type is one of this jsonp response may be created. */ public static final MediaTypeMap<String> jsonpCompatibleMediaTypes = new MediaTypeMap<String>(); /** * Default {@link ObjectMapper} for type resolution. Used if none is provided by {@link Providers}. */ protected static final ObjectMapper DEFAULT_MAPPER = new ObjectMapper(); static { jsonpCompatibleMediaTypes.add(MediaType.APPLICATION_JSON_TYPE , MediaType.APPLICATION_JSON_TYPE.toString()); jsonpCompatibleMediaTypes.add(APPLICATION_JAVASCRIPT_MEDIA_TYPE, APPLICATION_JAVASCRIPT_MEDIA_TYPE.toString()); jsonpCompatibleMediaTypes.add(APPLICATION_PLUS_JSON_TYPE , APPLICATION_PLUS_JSON_TYPE.toString()); jsonpCompatibleMediaTypes.add(TEXT_JSON_TYPE , TEXT_JSON_TYPE.toString()); jsonpCompatibleMediaTypes.add(TEXT_JAVASCRIPT_MEDIA_TYPE , TEXT_JAVASCRIPT_MEDIA_TYPE.toString()); } private UriInfo uri; private String callbackQueryParameter = DEFAULT_CALLBACK_QUERY_PARAMETER; /** * The {@link ObjectMapper} used to create typing information. */ protected ObjectMapper objectMapper; /** * The {@link Providers} used to retrieve the {@link #objectMapper} from. */ protected Providers providers; /** * {@inheritDoc} */ @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { LogMessages.LOGGER.debugf("Interceptor : %s, Method : aroundWriteTo", getClass().getName()); String function = uri.getQueryParameters().getFirst(callbackQueryParameter); if (function != null && !function.trim().isEmpty() && !jsonpCompatibleMediaTypes.getPossible(context.getMediaType()).isEmpty()){ OutputStreamWriter writer = new OutputStreamWriter(context.getOutputStream()); writer.write(function + "("); writer.flush(); context.proceed(); writer.write(")"); writer.flush(); } else { context.proceed(); } } /** * Search for an {@link ObjectMapper} for the given class and mediaType * * @param type the {@link Class} to serialize * @param mediaType the response {@link MediaType} * @return the {@link ObjectMapper} */ protected ObjectMapper getObjectMapper(Class<?> type, MediaType mediaType) { if (objectMapper != null) { return objectMapper; } if (providers != null) { ContextResolver<ObjectMapper> resolver = providers.getContextResolver(ObjectMapper.class, mediaType); if (resolver == null) { resolver = providers.getContextResolver(ObjectMapper.class, null); } if (resolver != null) { return resolver.getContext(type); } } return DEFAULT_MAPPER; } /** * Setter used by RESTeasy to provide the {@link UriInfo}. * * @param uri the uri to set */ @Context public void setUri(UriInfo uri) { this.uri = uri; } /** * Setter used by RESTeasy to provide the {@link Providers} * * @param providers */ @Context public void setProviders(Providers providers) { this.providers = providers; } /** * Set an fix {@link ObjectMapper}. If this is not set {@link Providers} are used for lookup. If there are is none too, use a default one. * * @param objectMapper */ public void setObjectMapper(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } /** * Get the name of the query parameter which contains the JavaScript method name. Default: callback. * * @return the callbackQueryParameter */ public String getCallbackQueryParameter() { return callbackQueryParameter; } /** * Set callback query parameter. * * @see #getCallbackQueryParameter() * @param callbackQueryParameter the callbackQueryParameter to set */ public void setCallbackQueryParameter(String callbackQueryParameter) { this.callbackQueryParameter = callbackQueryParameter; } }