Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/JAXRSOperationResourceValidator.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/JAXRSOperationResourceValidator.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/JAXRSOperationResourceValidator.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/JAXRSOperationResourceValidator.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,352 @@
+/*
+ * 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 com.ibm.ws.jaxrs.validation;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.utils.AnnotationUtils;
+
+import com.ibm.ws.jaxrs.i18n.Messages;
+
+/**
+ * This class will be responsible for validating a set of OperationResourceInfo
+ * objects created from a particular resource class. The validations done by
+ * this class are those listed in the JAX-RS specification.
+ *
+ */
+public class JAXRSOperationResourceValidator implements OperationResourceValidator {
+
+ public JAXRSOperationResourceValidator() {
+
+ }
+
+ /**
+ * This method will validate the list of OperationResourceInfo objects that
+ * the validator was supplied. A list of ValidationMessage objects will be
+ * returned containing any necessary messages.
+ *
+ */
+ public List<ValidationMessage> validate(List<OperationResourceInfo> infos) {
+ List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
+
+ checkMultipleDesignators(infos, messages);
+ for (OperationResourceInfo info : infos) {
+ checkMethodVisibility(info, messages);
+ checkParams(info, messages);
+ checkFormParameters(info, messages);
+ }
+
+ return messages;
+ }
+
+ /**
+ * This method will check to ensure that multiple methods are not annotated
+ * with the same request designator unless one has the @Path annotation. It
+ * will also check to see that methods annotated with a request designator
+ * and an @Path annotation have different path values.
+ *
+ * @param messages
+ */
+ void checkMultipleDesignators(List<OperationResourceInfo> infos, List<ValidationMessage> messages) {
+
+ Map<String, List<OperationResourceInfo>> methodTypeMap = new HashMap<String, List<OperationResourceInfo>>();
+
+ Map<String, List<OperationResourceInfo>> pathMap = new HashMap<String, List<OperationResourceInfo>>();
+
+ // first initialize the mapping of http methods and paths to OperationResourceInfos
+ // we only create the mapping for methods that do not have the @Path annotation
+ for (OperationResourceInfo info : infos) {
+ String httpMethod = info.getHttpMethod();
+ if (httpMethod != null && !"".equals(httpMethod)
+ && !info.isSubResourceLocator()
+ && !info.isSubResourceMethod()) {
+ List<OperationResourceInfo> values = methodTypeMap
+ .get(httpMethod);
+ if (values == null) {
+ values = new ArrayList<OperationResourceInfo>();
+ methodTypeMap.put(httpMethod, values);
+ }
+ values.add(info);
+ }
+ String pathValue = info.getPath();
+ if (pathValue != null) {
+ String key = pathValue
+ + ":"
+ + (info.getHttpMethod() != null ? info.getHttpMethod()
+ : "");
+ List<OperationResourceInfo> values = pathMap.get(key);
+ if (values == null) {
+ values = new ArrayList<OperationResourceInfo>();
+ pathMap.put(key, values);
+ }
+ values.add(info);
+ }
+ }
+
+ // now make sure that for each method, we don't have more than
+ // one OperationResourceInfo
+ if (!methodTypeMap.isEmpty()) {
+ Iterator<Entry<String, List<OperationResourceInfo>>> entries = methodTypeMap
+ .entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry<String, List<OperationResourceInfo>> entry = entries
+ .next();
+ List<OperationResourceInfo> values = entry.getValue();
+ String httpMethod = entry.getKey();
+ if (values != null && values.size() > 1) {
+ int size = values.size();
+ boolean isWarningEmitted = false;
+ for (int firstIndex = 0; firstIndex < size; ++firstIndex) {
+ for (int secondIndex = firstIndex + 1; secondIndex < size; ++secondIndex) {
+ boolean isConsumesCompatible = false;
+ Set<MediaType> firstConsumesSet = new HashSet<MediaType>(
+ values.get(firstIndex).getConsumes());
+ Set<MediaType> secondConsumesSet = new HashSet<MediaType>(
+ values.get(secondIndex).getConsumes());
+ for (MediaType firstConsumes : firstConsumesSet) {
+ for (MediaType secondConsumes : secondConsumesSet) {
+ if (firstConsumes
+ .isCompatible(secondConsumes)) {
+ isConsumesCompatible = true;
+ }
+ }
+ }
+
+ boolean isProducesCompatible = false;
+ Set<MediaType> firstProducesSet = new HashSet<MediaType>(
+ values.get(firstIndex).getProduces());
+ Set<MediaType> secondProducesSet = new HashSet<MediaType>(
+ values.get(secondIndex).getProduces());
+ for (MediaType firstProduces : firstProducesSet) {
+ for (MediaType secondProduces : secondProducesSet) {
+ if (firstProduces
+ .isCompatible(secondProduces)) {
+ isProducesCompatible = true;
+ }
+ }
+ }
+
+ if (isConsumesCompatible && isProducesCompatible) {
+ isWarningEmitted = true;
+ break;
+ }
+ }
+ }
+
+ if (isWarningEmitted) {
+ ValidationMessage message = new ValidationMessage(
+ ValidationMessage.Type.WARNING);
+ StringBuffer sb = new StringBuffer();
+ for (OperationResourceInfo value : values) {
+ sb.append(" ").append(
+ value.getMethodToInvoke().getName());
+ }
+ String msg = Messages.getMessage(
+ "multipleRequestDesignators", httpMethod, sb
+ .toString(), values.get(0)
+ .getClassResourceInfo()
+ .getServiceClass().getName());
+ message.setMessage(msg);
+ messages.add(message);
+ }
+ }
+ }
+ }
+
+ // let's make sure we don't have duplicate entries with the same @Path value
+ // unless the request designator is different
+ if (!pathMap.isEmpty()) {
+ Iterator<Entry<String, List<OperationResourceInfo>>> entries = pathMap
+ .entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry<String, List<OperationResourceInfo>> entry = entries
+ .next();
+ List<OperationResourceInfo> values = entry.getValue();
+ String path = entry.getKey();
+ if (values != null && values.size() > 1) {
+ ValidationMessage message = new ValidationMessage(
+ ValidationMessage.Type.WARNING);
+ StringBuffer sb = new StringBuffer();
+ path = path.substring(0, path.indexOf(":"));
+ for (OperationResourceInfo value : values) {
+ sb.append(" ").append(
+ value.getMethodToInvoke().getName());
+ }
+ String msg = Messages.getMessage("pathAnnotFail01", path,
+ sb.toString(), values.get(0).getClassResourceInfo()
+ .getServiceClass().getName());
+ message.setMessage(msg);
+ messages.add(message);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method will check to see if a method is annotated with a request
+ * designator or an @Path annotation and is not public. If this condition is
+ * found, a warning will be created.
+ *
+ */
+ void checkMethodVisibility(OperationResourceInfo info, List<ValidationMessage> messages) {
+ Method method = info.getMethodToInvoke();
+ boolean pathFound = info.getPath() != null;
+
+ // if a request designator or @Path annotation is found, check the
+ // visiblity
+ if ((info.getHttpMethod() != null && !"".equals(info.getHttpMethod()))
+ || pathFound) {
+ if (!Modifier.isPublic(method.getModifiers())) {
+ ValidationMessage message = new ValidationMessage(
+ ValidationMessage.Type.WARNING);
+ message
+ .setMessage(Messages.getMessage("methodNotPublic",
+ method.getName(), method.getDeclaringClass()
+ .getName()));
+ messages.add(message);
+ }
+ }
+
+ }
+
+ /**
+ * This method will check that a given resource method does not contain more
+ * than one entity parameter. If more than one entity parameter is found, an
+ * error will be created.
+ *
+ */
+ void checkParams(OperationResourceInfo info, List<ValidationMessage> messages) {
+ Method method = info.getMethodToInvoke();
+ Class<?>[] params = method.getParameterTypes();
+ Annotation[][] allParamAnnots = method.getParameterAnnotations();
+ int nonAnnotatedParams = 0;
+ for (int i = 0; i < params.length; ++i) {
+ if (i >= allParamAnnots.length) {
+ nonAnnotatedParams++;
+ } else {
+ Annotation[] paramAnnots = allParamAnnots[i];
+
+ // indicates whether or not we find an appropriate annotation
+ // on the parameter
+ boolean annotFound = false;
+ for (Annotation paramAnnot : paramAnnots) {
+ if (AnnotationUtils.isParamAnnotationClass(paramAnnot
+ .annotationType())) {
+ annotFound = true;
+ break;
+ }
+ }
+
+ // if we didn't find one, update our count of non-annotated
+ // params
+ if (!annotFound) {
+ nonAnnotatedParams++;
+ }
+ }
+ }
+
+ if (nonAnnotatedParams > 1) {
+ ValidationMessage message = new ValidationMessage(
+ ValidationMessage.Type.ERROR);
+ message.setMessage(Messages.getMessage("invalidEntityParam00",
+ method.getName(), method.getDeclaringClass().getName()));
+ messages.add(message);
+ }
+ }
+
+ void checkFormParameters(OperationResourceInfo info, List<ValidationMessage> messages) {
+ ClassResourceInfo resource = info.getClassResourceInfo();
+ boolean foundFormParam = false;
+ if (!foundFormParam) {
+ foundFormParam = isFormParamFound(resource.getParameterMethods());
+ }
+
+ if (!foundFormParam) {
+ foundFormParam = isFormParamFound(resource.getParameterFields());
+ }
+
+ Method m = info.getAnnotatedMethod();
+ Annotation[][] paramAnnotations = m.getParameterAnnotations();
+ Class<?> typeOfEntity = null;
+ for (int c = 0; c < paramAnnotations.length; ++c) {
+ if (paramAnnotations[c].length == 0) {
+ // found entity
+ typeOfEntity = m.getParameterTypes()[c];
+ } else {
+ foundFormParam = foundFormParam ? true
+ : findFormParam(paramAnnotations[c]);
+ }
+ }
+
+ if (foundFormParam) {
+ if (typeOfEntity != null) {
+ if (!MultivaluedMap.class.isAssignableFrom(typeOfEntity)) {
+ ValidationMessage message = new ValidationMessage(
+ ValidationMessage.Type.ERROR);
+ String msg = Messages.getMessage("invalidEntityParam01", m
+ .getName(), m.getDeclaringClass().getName());
+ message.setMessage(msg);
+ messages.add(message);
+ }
+ }
+ }
+
+ }
+
+ private static boolean isFormParamFound(List<? extends AnnotatedElement> annotatedElements) {
+ if (annotatedElements.size() > 0) {
+ for (AnnotatedElement e : annotatedElements) {
+ Annotation[] annotations = e.getAnnotations();
+ if (annotations.length != 0) {
+ if (findFormParam(annotations)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean findFormParam(Annotation[] annotations) {
+ for (Annotation a : annotations) {
+ if (FormParam.class.isAssignableFrom(a.annotationType())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/OperationResourceValidator.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/OperationResourceValidator.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/OperationResourceValidator.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/OperationResourceValidator.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,41 @@
+/*
+ * 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 com.ibm.ws.jaxrs.validation;
+
+import java.util.List;
+
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+
+/**
+ * This interface will be implemented by classes that provide validation
+ * function on a set of OperationResourceInfo objects.
+ *
+ */
+public interface OperationResourceValidator {
+
+ /**
+ * This method will validate the set of OperationResourceInfo objects that
+ * are provided. It will return a list of ValidationMessage objects that
+ * represent any validation error, warning, or debug messages.
+ *
+ */
+ public List<ValidationMessage> validate(List<OperationResourceInfo> infos);
+
+}
\ No newline at end of file
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/RESTValidator.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/RESTValidator.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/RESTValidator.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/RESTValidator.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,111 @@
+/*
+ * 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 com.ibm.ws.jaxrs.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+
+import com.ibm.ws.jaxrs.i18n.Messages;
+import com.ibm.ws.jaxrs.model.JAXRSInfoOutput;
+import com.ibm.ws.jaxrs.validation.ValidationMessage.Type;
+
+/**
+ * This class will be responsible for encapsulating the validation that
+ * takes place on a given instance of RESTInfoOutput. This will drive
+ * the validation of resource classes and methods.
+ *
+ */
+public class RESTValidator {
+
+ private static Log log = LogFactory.getLog(RESTValidator.class);
+
+ private static List<ClassResourceValidator> classValidators = new ArrayList<ClassResourceValidator>();
+
+ private static List<OperationResourceValidator> opValidators = new ArrayList<OperationResourceValidator>();
+
+ // add the default validators
+ static {
+ classValidators.add(new JAXRSClassResourceValidator());
+ opValidators.add(new JAXRSOperationResourceValidator());
+ }
+
+ /**
+ * This will drive the call of the validators for resource classes and methods.
+ *
+ */
+ public static void validateOutput(JAXRSInfoOutput output) throws Exception {
+ List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
+ List<ClassResourceInfo> classInfos = output.getClassInfoList();
+
+ if (classInfos != null && !classInfos.isEmpty()) {
+
+ // first drive the validation of the resource classes
+ for (ClassResourceValidator classValidator : classValidators) {
+ messages.addAll(classValidator.validate(classInfos));
+ }
+
+ // now drive the resolution of resource methods
+ for (ClassResourceInfo classInfo : classInfos) {
+ List<OperationResourceInfo> opInfos = new ArrayList<OperationResourceInfo>(
+ classInfo.getMethodDispatcher()
+ .getOperationResourceInfos());
+ if (!opInfos.isEmpty()) {
+ for (OperationResourceValidator opValidator : opValidators) {
+ messages.addAll(opValidator.validate(opInfos));
+ }
+ }
+ }
+ }
+
+ // now let's do the necessary reporting
+ boolean errorFound = false;
+ for (ValidationMessage message : messages) {
+ Type messageType = message.getMessageType();
+ if (messageType.equals(Type.ERROR)) {
+ errorFound = true;
+ }
+ if (messageType.equals(Type.ERROR)) {
+ if (log.isErrorEnabled()) {
+ log.error(message.getMessage());
+ }
+ } else if (messageType.equals(Type.WARNING)) {
+ if (log.isWarnEnabled()) {
+ log.warn(message.getMessage());
+ }
+ } else if (messageType.equals(Type.DEBUG)) {
+ if (log.isDebugEnabled()) {
+ log.debug(message.getMessage());
+ }
+ }
+ }
+
+ if (errorFound) {
+ throw new ResourceValidationException(Messages
+ .getMessage("genericValidationError"));
+ }
+
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ResourceValidationException.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ResourceValidationException.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ResourceValidationException.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ResourceValidationException.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,47 @@
+/*
+ * 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 com.ibm.ws.jaxrs.validation;
+
+/**
+ * This is a custom exception classes for validation errors that are found
+ * when processing resource classes and methods.
+ *
+ */
+public class ResourceValidationException extends Exception {
+
+ private static final long serialVersionUID = -4863356847734034433L;
+
+ public ResourceValidationException() {
+ super();
+ }
+
+ public ResourceValidationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ResourceValidationException(String message) {
+ super(message);
+ }
+
+ public ResourceValidationException(Throwable cause) {
+ super(cause);
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ValidationMessage.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ValidationMessage.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ValidationMessage.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/validation/ValidationMessage.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,58 @@
+/*
+ * 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 com.ibm.ws.jaxrs.validation;
+
+/**
+ * This class will be used to represent a message that is created
+ * during validation of REST classes.
+ *
+ */
+public class ValidationMessage {
+
+ // indicates the type of message the instance represents
+ public enum Type {
+ ERROR, WARNING, DEBUG
+ }
+
+ private String message;
+
+ private Type messageType;
+
+ public ValidationMessage(Type messageType) {
+ this.messageType = messageType;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Type getMessageType() {
+ return messageType;
+ }
+
+ public void setMessageType(Type messageType) {
+ this.messageType = messageType;
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/RESTServlet.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/RESTServlet.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/RESTServlet.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/RESTServlet.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,439 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+
+import com.ibm.ws.jaxrs.context.ContextConstants;
+import com.ibm.ws.jaxrs.context.RESTContext;
+import com.ibm.ws.jaxrs.engine.RESTEngine;
+import com.ibm.ws.jaxrs.integration.ApplicationProvider;
+import com.ibm.ws.jaxrs.integration.DefaultJAXRSProviderCacheProvider;
+import com.ibm.ws.jaxrs.integration.IntegrationRegistry;
+import com.ibm.ws.jaxrs.integration.JAXRSProviderCacheProvider;
+import com.ibm.ws.jaxrs.integration.MetaDataProvider;
+import com.ibm.ws.jaxrs.integration.OptionsResponseProvider;
+import com.ibm.ws.jaxrs.integration.ResponseWriter;
+import com.ibm.ws.jaxrs.provider.JAXBOptionsResponseProvider;
+
+/**
+ * This is the servlet that will receive REST requests and route them as needed
+ * to the runtime.
+ *
+ */
+public class RESTServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 41205902322406552L;
+
+ private static final Log log = LogFactory.getLog(RESTServlet.class);
+
+ private boolean metadataInitialized = false;
+
+ private ServletConfig servletConfig;
+
+ public RESTServlet() {
+ super();
+ }
+
+ // unit testing constructor
+ public RESTServlet(Class<?>... resourceClasses) throws ServletException {
+ buildRESTInfo(null, resourceClasses);
+ }
+
+ @Override
+ public void doDelete(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Received DELETE request for: "
+ + req.getRequestURL().toString());
+ }
+ processHttpRequest(req, resp);
+ }
+
+ @Override
+ public void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Received GET request for: "
+ + req.getRequestURL().toString());
+ }
+ processHttpRequest(req, resp);
+ }
+
+ @Override
+ public void doOptions(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Received OPTIONS request for: "
+ + req.getRequestURL().toString());
+ }
+ processHttpRequest(req, resp);
+ }
+
+ @Override
+ public void doHead(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Received HEAD request for: "
+ + req.getRequestURL().toString());
+ }
+ super.doHead(req, resp);
+ }
+
+ @Override
+ public void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Received POST request for: "
+ + req.getRequestURL().toString());
+ }
+ processHttpRequest(req, resp);
+ }
+
+ @Override
+ public void doPut(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("Received PUT request for: "
+ + req.getRequestURL().toString());
+ }
+ processHttpRequest(req, resp);
+ }
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+ this.servletConfig = config;
+ try {
+ buildRESTInfo(config, new Class[] {});
+ } catch (ServletException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ServletException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ IntegrationRegistry.removeIntegrationProvider(servletConfig, null);
+ }
+
+ /**
+ * This method will initialize the needed REST metadata that will be used to
+ * serve incoming request to this servlet.
+ *
+ */
+ void buildRESTInfo(ServletConfig config, Class<?>... resourceClasses)
+ throws ServletException {
+ if (!metadataInitialized) {
+ try {
+ ApplicationProvider appProvider = new ServletApplicationProvider(
+ config, Thread.currentThread().getContextClassLoader(),
+ resourceClasses);
+ IntegrationRegistry.addIntegrationProvider(config,
+ ApplicationProvider.class, appProvider);
+ metadataInitialized = true;
+ } catch (Exception e) {
+ throw new ServletException(e.getMessage(), e);
+ }
+
+ // add servlet response writer
+ IntegrationRegistry.addIntegrationProvider(servletConfig,
+ ResponseWriter.class, ServletResponseWriter.getInstance());
+
+ // add our class responsible for caching
+ IntegrationRegistry.addIntegrationProvider(servletConfig,
+ MetaDataProvider.class, new ServletMetadataProvider());
+
+ // add provider factory cache
+ IntegrationRegistry.addIntegrationProvider(servletConfig,
+ JAXRSProviderCacheProvider.class,
+ new DefaultJAXRSProviderCacheProvider());
+
+ // add our OPTIONS response provider
+ IntegrationRegistry.addIntegrationProvider(servletConfig,
+ OptionsResponseProvider.class, JAXBOptionsResponseProvider
+ .getInstance(), true);
+
+ }
+ }
+
+ /*
+ * This method drives the request processing for all invocation types.
+ */
+ private void processHttpRequest(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException {
+ try {
+ RESTContext context = new RESTContext();
+ initContext(request, response, context);
+ RESTEngine.invoke(context);
+ } catch (Throwable e) {
+ throw new ServletException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * This method will initialize various properties on the RESTContext that are
+ * derived from the current request.
+ */
+ void initContext(HttpServletRequest request, HttpServletResponse response, RESTContext context)
+ throws IOException, Exception {
+
+ // set the request and response on the context
+ context.setProperty(ContextConstants.SERVLET_REQUEST, request);
+ context.setProperty(ContextConstants.SERVLET_RESPONSE, response);
+
+ // set the ServletContext and ServletConfig on the context
+ try {
+ context.setProperty(ContextConstants.SERVLET_CONTEXT, servletConfig
+ .getServletContext());
+ } catch (Throwable t) {
+ /* this is only a test framework issue */
+ }
+
+ context.setProperty(ContextConstants.SERVLET_CONFIG, servletConfig);
+
+ context.setProperty(ContextConstants.HTTP_ACCEPT_HEADER, request
+ .getHeader(HttpHeaders.ACCEPT));
+ context.setProperty(ContextConstants.HTTP_METHOD, request.getMethod());
+
+ context.setProperty(ContextConstants.CONTENT_TYPE, request
+ .getContentType());
+ context.setProperty(ContextConstants.HTTP_PATH_INFO,
+ normalizeURIValue(request.getPathInfo()));
+ context.setProperty(ContextConstants.HTTP_REQUEST_ENCODING, request
+ .getCharacterEncoding());
+ context.setProperty(ContextConstants.HTTP_REQUEST_URI,
+ normalizeURIValue(request.getRequestURI()));
+ context.setProperty(ContextConstants.HTTP_REQUEST_URL,
+ normalizeURIValue(request.getRequestURL().toString()));
+ context.setProperty(ContextConstants.HTTP_REQUEST_CONTEXT_PATH, request
+ .getContextPath());
+ context.setProperty(ContextConstants.HTTP_QUERY_STRING, request
+ .getQueryString());
+ context.setProperty(ContextConstants.AUTHENTICATION_SCHEME, request
+ .getAuthType());
+ context.setProperty(ContextConstants.USER_PRINCIPAL, request
+ .getUserPrincipal());
+ context.setProperty(ContextConstants.REQUEST_SECURE, Boolean
+ .valueOf(request.isSecure()));
+ context.setProperty(ContextConstants.CONTENT_LANGUAGE, request
+ .getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ context.setProperty(ContextConstants.HTTP_REQUEST_LOCALE, request
+ .getLocale());
+ context.setProperty(ContextConstants.REQUEST_INPUT_STREAM, request
+ .getInputStream());
+ context.setProperty(ContextConstants.RESPONSE_OUTPUT_STREAM, response
+ .getOutputStream());
+ context.setProperty(ContextConstants.CONTEXT_CLASSLOADER, Thread
+ .currentThread().getContextClassLoader());
+ context.setProperty(ContextConstants.METADATA_KEY,
+ servletConfig != null ? servletConfig.getServletName() : null);
+
+ // set the config file URL if the servlet-config parameter is set
+ String fileLoc = servletConfig != null ? servletConfig
+ .getInitParameter("com.ibm.ws.jaxrs.ConfigFile") : null;
+ if (log.isDebugEnabled()) {
+ log.debug("IBM config file init parameter value is : " + fileLoc);
+ }
+ if (fileLoc != null && !"".equals(fileLoc)) {
+ File file = new File(fileLoc);
+ URL url = null;
+ if (!file.exists()) {
+ url = Thread.currentThread().getContextClassLoader()
+ .getResource(fileLoc);
+ if (url == null) {
+ if (!fileLoc.startsWith("/")) {
+ fileLoc = "/" + fileLoc;
+ }
+ url = servletConfig.getServletContext()
+ .getResource(fileLoc);
+ if (log.isDebugEnabled()) {
+ log.debug("IBM config file on servlet context path : "
+ + url);
+ }
+ } else {
+ if (log.isDebugEnabled()) {
+ log
+ .debug("IBM config file exists on classloader path : "
+ + url);
+ }
+ }
+ } else {
+ url = file.toURI().toURL();
+ if (log.isDebugEnabled()) {
+ log.debug("IBM config file exists on file system path : "
+ + url);
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("IBM config file setting is set to URL : " + url);
+ }
+ context.setProperty(ContextConstants.CONFIG_FILE_URL, url);
+ }
+
+ context.setProperty(ContextConstants.HTTP_PATH_RESOURCE,
+ getPath(request));
+
+ // initialize the query string values
+ MultivaluedMap<String, String> queryValuesDecoded = JAXRSUtils
+ .getStructuredParams(request.getQueryString(), "&", true);
+ MultivaluedMap<String, String> queryValuesEncoded = JAXRSUtils
+ .getStructuredParams(request.getQueryString(), "&", false);
+ context.setProperty(ContextConstants.QUERY_STRING_DECODED_VALUES,
+ queryValuesDecoded);
+ context.setProperty(ContextConstants.QUERY_STRING_ENCODED_VALUES,
+ queryValuesEncoded);
+
+ // initialize the HTTP headers
+ Map<String, List<String>> headers = getHeaders(request);
+ MultivaluedMap<String, String> headerValues = new MetadataMap<String, String>(
+ headers);
+ context.setProperty(ContextConstants.HTTP_HEADER_VALUES, headerValues);
+
+ // initialize the matrix parameters (both encoded/decoded)
+ context
+ .setProperty(ContextConstants.MATRIX_PARAMETER_VALUES_DECODED,
+ JAXRSUtils.getMatrixParams(URI.create(
+ request.getRequestURL().toString())
+ .getRawPath(), true));
+ context.setProperty(ContextConstants.MATRIX_PARAMETER_VALUES_ENCODED,
+ JAXRSUtils
+ .getMatrixParams(URI.create(
+ request.getRequestURL().toString())
+ .getRawPath(), false));
+
+ // initialize the cookie array, convert the servlet cookies into JAX-RS style cookies
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ Map<String, javax.ws.rs.core.Cookie> cookieMap = new HashMap<String, javax.ws.rs.core.Cookie>();
+ for (Cookie cookie : cookies) {
+ javax.ws.rs.core.Cookie jaxrsCookie = new javax.ws.rs.core.Cookie(
+ cookie.getName(), cookie.getValue(), cookie.getPath(),
+ cookie.getDomain(), cookie.getVersion());
+ cookieMap.put(cookie.getName(), jaxrsCookie);
+ }
+ context.setProperty(ContextConstants.HTTP_COOKIES, cookieMap);
+ }
+
+ // store all the acceptable Locales
+ List<Locale> locales = new ArrayList<Locale>();
+ Enumeration<Locale> localeEnum = request.getLocales();
+ if (localeEnum != null) {
+ while (localeEnum.hasMoreElements()) {
+ locales.add(localeEnum.nextElement());
+ }
+ context.setProperty(ContextConstants.HTTP_REQUEST_LOCALES, locales);
+ }
+
+ context.setProperty(ContextConstants.INTEGRATION_REGISTRATION_KEY,
+ servletConfig);
+ }
+
+ /**
+ * This method will return the path for the current request. This will contain
+ * all the parts after the context path, and the string will be encoded.
+ *
+ */
+ private String getPath(HttpServletRequest request) {
+ // normalize this value in the rare cases where someone has
+ // (/someresourcepath/../someresourcepath)
+ String path = URI.create(request.getRequestURL().toString())
+ .normalize().getRawPath();
+ if (request.getContextPath() != null
+ && path.indexOf(request.getContextPath()) != -1) {
+ String cp = request.getContextPath();
+ int cpLength = cp.length();
+ path = path.substring(path.indexOf(cp) + cpLength);
+ }
+
+ return path;
+ }
+
+ /**
+ * Normalize a given URI value and return it.
+ * @param value the value
+ * @return the normalized value if possible, if not possible, return what was sent in
+ */
+ private String normalizeURIValue(String value) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ URI normalizedURI = new URI(value).normalize();
+ return normalizedURI.toString();
+ } catch (URISyntaxException e) {
+ // could this happen if the request message was made to the runtime already?
+ // maybe someone set up the request wrong
+ }
+ return value;
+ }
+
+ /**
+ * This method retrieves all the headers and establishes a multivalued map
+ * that is stored on the RESTContext.
+ *
+ */
+ private Map<String, List<String>> getHeaders(HttpServletRequest request) {
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+ Enumeration headerNames = request.getHeaderNames();
+ if (headerNames != null) {
+ while (headerNames.hasMoreElements()) {
+ String headerName = (String) headerNames.nextElement();
+ List<String> headerValueList = new ArrayList<String>();
+ Enumeration headerValues = request.getHeaders(headerName);
+ if (headerValues != null) {
+ while (headerValues.hasMoreElements()) {
+ headerValueList
+ .add((String) headerValues.nextElement());
+ }
+ }
+ headerName = headerName.toLowerCase();
+ headers.put(headerName, headerValueList);
+ }
+ }
+ return headers;
+ }
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletApplicationProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletApplicationProvider.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletApplicationProvider.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletApplicationProvider.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,175 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.Application;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.ibm.ws.jaxrs.context.ContextConstants;
+import com.ibm.ws.jaxrs.context.RESTContext;
+import com.ibm.ws.jaxrs.i18n.Messages;
+import com.ibm.ws.jaxrs.integration.ApplicationProvider;
+import com.ibm.ws.jaxrs.integration.DefaultApplication;
+import com.ibm.ws.jaxrs.utils.ClassUtils;
+import com.ibm.ws.jaxrs.web.asm.JAXRSAnnotationScanner;
+
+/**
+ * This is our servlet-based implementation of the ApplicationProvider. It
+ * will look for an init-parameter in the config that specifies the name
+ * of the JAX-RS Application subclass.
+ *
+ */
+public class ServletApplicationProvider implements ApplicationProvider {
+
+ private static final Log log = LogFactory
+ .getLog(ServletApplicationProvider.class);
+
+ private ServletConfig servletConfig;
+
+ private ClassLoader classLoader;
+
+ private Class<?>[] resourceClasses;
+
+ public ServletApplicationProvider(ServletConfig servletConfig, ClassLoader classLoader, Class<?>... resourceClasses) {
+ this.servletConfig = servletConfig;
+ this.classLoader = classLoader;
+ this.resourceClasses = resourceClasses;
+ }
+
+ /**
+ * Returns the Application subclass that is specified in the init-param
+ */
+ public List<Application> getApplicationClasses(RESTContext context)
+ throws Exception {
+ List<Application> applications = new ArrayList<Application>();
+ if (servletConfig == null && resourceClasses != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Generating application wrapper class");
+ }
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ for (Class<?> resourceClass : resourceClasses) {
+ classes.add(resourceClass);
+ }
+ applications.add(new DefaultApplication(classes, null));
+ } else {
+ String appClassName = servletConfig
+ .getInitParameter("javax.ws.rs.Application");
+ boolean appClassesFound = false;
+ if (appClassName != null && !"".equals(appClassName)) {
+ try {
+ Class<?> application = classLoader.loadClass(appClassName);
+ Application app = (Application) ClassUtils
+ .newInstance(application);
+ if (app != null) {
+
+ // only process this Application subclass if it gives a non-empty
+ // set of singletons or classes
+ if ((app.getClasses() != null && !app.getClasses()
+ .isEmpty())
+ || (app.getSingletons() != null && !app
+ .getSingletons().isEmpty())) {
+ if (log.isDebugEnabled()) {
+ log
+ .debug("Loaded javax.ws.rs.core.Application subclass "
+ + "instance: " + appClassName);
+ }
+ applications.add(app);
+ appClassesFound = true;
+ }
+ }
+
+ } catch (Exception e) {
+ log.error(Messages.getMessage("processAppError"), e);
+ throw e;
+ }
+ }
+ if (!appClassesFound) {
+ if (log.isDebugEnabled()) {
+ log
+ .debug("Classes in the web app will be scanned for JAX-RS annotations");
+ }
+ ServletContext servletContext = servletConfig
+ .getServletContext();
+ if (servletContext != null) {
+ ClassLoader cl = (ClassLoader) context
+ .getProperty(ContextConstants.CONTEXT_CLASSLOADER);
+ List<InputStream> classStreams = getInputStreamsFromContext(
+ servletContext, cl);
+ JAXRSAnnotationScanner scanner = new JAXRSAnnotationScanner();
+ Application app = scanner.scan(classStreams, cl);
+ if (app != null && app.getClasses() != null
+ && !app.getClasses().isEmpty()) {
+ if (log.isDebugEnabled()) {
+ log
+ .debug("Found JAX-RS classes during annotation scanning");
+ }
+ applications.add(app);
+ }
+ }
+ }
+ }
+ return applications;
+ }
+
+ /*
+ * Collects InputStreams to .class files within a web application.
+ */
+ List<InputStream> getInputStreamsFromContext(ServletContext servletContext, ClassLoader cl) {
+ List<InputStream> classStreams = new ArrayList<InputStream>();
+ List<String> classResourcePaths = new ArrayList<String>();
+ getClassResourcePaths(servletContext, "/WEB-INF/classes/",
+ classResourcePaths);
+ for (String classResourcePath : classResourcePaths) {
+ InputStream is = cl.getResourceAsStream(classResourcePath);
+ if (is != null) {
+ classStreams.add(is);
+ }
+ }
+ return classStreams;
+ }
+
+ /*
+ * Recursive method to gather the full path to all .class files found
+ * in the WEB-INF/classes folder of a web application.
+ */
+ void getClassResourcePaths(ServletContext servletContext, String path, List<String> classResourcePaths) {
+ Set paths = servletContext.getResourcePaths(path);
+ if (paths != null) {
+ for (Object obj : paths) {
+ String p = (String) obj;
+ if (p.endsWith("/")) {
+ getClassResourcePaths(servletContext, p, classResourcePaths);
+ } else if (p.endsWith(".class")) {
+ classResourcePaths.add(p);
+ }
+ }
+ }
+ }
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletMetadataProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletMetadataProvider.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletMetadataProvider.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletMetadataProvider.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,134 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.core.Application;
+
+import com.ibm.ws.jaxrs.context.ContextConstants;
+import com.ibm.ws.jaxrs.context.RESTContext;
+import com.ibm.ws.jaxrs.i18n.Messages;
+import com.ibm.ws.jaxrs.integration.ApplicationProvider;
+import com.ibm.ws.jaxrs.integration.IntegrationRegistry;
+import com.ibm.ws.jaxrs.integration.MetaDataProvider;
+import com.ibm.ws.jaxrs.metadata.RESTMetaData;
+import com.ibm.ws.jaxrs.model.ApplicationProcessor;
+import com.ibm.ws.jaxrs.model.JAXRSInfoOutput;
+
+/**
+ * This is an implementation of the MetadataCacheProvider that will be used
+ * in the common component web container environment. It may be overridden
+ * by consumers of the REST runtime to provide a more robust cache mechanism.
+ *
+ */
+public class ServletMetadataProvider implements MetaDataProvider {
+
+ private final Map<String, RESTMetaData> cache;
+
+ public ServletMetadataProvider() {
+ cache = new ConcurrentHashMap<String, RESTMetaData>();
+ }
+
+ public RESTMetaData getRESTMetaData(String metadataKey) {
+ return cache.get(metadataKey);
+ }
+
+ public RESTMetaData buildRESTMetaData(String metadataKey, RESTContext context)
+ throws Exception {
+ synchronized (cache) {
+ RESTMetaData metaData = cache.get(metadataKey);
+ if (metaData == null) {
+ metaData = buildMetaData(context);
+ cache.put(metadataKey, metaData);
+ }
+ return metaData;
+ }
+ }
+
+ /**
+ * This method will be responsible for driving the calls to build up an instance
+ * of RESTMetaData for the current request.
+ *
+ */
+ private RESTMetaData buildMetaData(RESTContext context) throws Exception {
+ RESTMetaData metaData = new RESTMetaData();
+
+ // we need to get an ApplicationProvider so we know the source of the metadata
+ ApplicationProvider appProvider = (ApplicationProvider) IntegrationRegistry
+ .getIntegrationProvider(
+ context
+ .getProperty(ContextConstants.INTEGRATION_REGISTRATION_KEY),
+ ApplicationProvider.class);
+ if (appProvider == null) {
+ throw new RuntimeException(Messages.getMessage("invalidMetaData00",
+ (String) context
+ .getProperty(ContextConstants.HTTP_PATH_INFO)));
+ }
+
+ List<Application> applications = appProvider
+ .getApplicationClasses(context);
+
+ URL configURL = (URL) context
+ .getProperty(ContextConstants.CONFIG_FILE_URL);
+
+ ClassLoader classLoader = (ClassLoader) context
+ .getProperty(ContextConstants.CONTEXT_CLASSLOADER);
+
+ // list must be non-null and non-empty
+ if ((applications == null || applications.isEmpty())
+ && configURL == null) {
+ throw new IllegalArgumentException(Messages.getMessage(
+ "invalidMetaData01", appProvider.getClass().getName()));
+ }
+
+ if (applications != null && !applications.isEmpty()) {
+ for (Application application : applications) {
+ createMetadata(application, configURL, classLoader, metaData);
+ }
+ } else {
+ createMetadata(null, configURL, classLoader, metaData);
+ }
+
+ return metaData;
+ }
+
+ /**
+ * Method to drive the building and storing of metadata for the runtime.
+ */
+ private void createMetadata(Application application, URL configURL, ClassLoader classLoader, RESTMetaData metaData)
+ throws Exception {
+ ApplicationProcessor processor = new ApplicationProcessor(configURL,
+ classLoader);
+ JAXRSInfoOutput output = processor.processApplication(application);
+
+ // now add both the resource and provider information
+ if (output.getClassInfoList() != null) {
+ metaData.getClassInfoList().addAll(output.getClassInfoList());
+ }
+ if (output.getProviderInfoList() != null) {
+ metaData.getProviderInfoList().addAll(output.getProviderInfoList());
+ }
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletResponseWriter.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletResponseWriter.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletResponseWriter.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletResponseWriter.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,230 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web;
+
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.activation.DataContentHandler;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.ibm.ws.jaxrs.context.ContextConstants;
+import com.ibm.ws.jaxrs.context.RESTContext;
+import com.ibm.ws.jaxrs.i18n.Messages;
+import com.ibm.ws.jaxrs.integration.ResponseWriter;
+import com.ibm.ws.jaxrs.io.LogOutputStream;
+
+/**
+ * This is the default implementation of the ResponseWriter interface
+ * supplied by the core runtime.
+ *
+ */
+public class ServletResponseWriter implements ResponseWriter {
+
+ private static final Log log = LogFactory
+ .getLog(ServletResponseWriter.class);
+
+ private static final ServletResponseWriter singleton = new ServletResponseWriter();
+
+ public static ServletResponseWriter getInstance() {
+ return singleton;
+ }
+
+ /**
+ * Called before the response is written to the OutputStream. This method will
+ * set the headers and status on the servlet response.
+ */
+ public void preWrite(RESTContext context) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.preWrite(): entry");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.preWrite(): exit");
+ }
+ }
+
+ /**
+ * Calls the DataHandler to serialize to the OutputStream.
+ */
+ public void writeWithDataHandler(RESTContext context, Object object, String mimeType, DataContentHandler contentHandler, OutputStream os)
+ throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.writeWithDataHandler(): entry");
+ }
+ Response response = (Response) context
+ .getProperty(ContextConstants.RESPONSE);
+ MultivaluedMap<String, Object> headers = (response == null) ? null
+ : response.getMetadata();
+ contentHandler.writeTo(object, mimeType, new ServletStatusOutputStream(
+ context, headers, os, -1, mimeType));
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.writeWithDataHandler(): exit");
+ }
+ }
+
+ /**
+ * Calls the MessageBodyWriter to serialize to the OutputStream.
+ */
+ public void writeWithEntityProvider(RESTContext context, MessageBodyWriter writer, Object responseObject, Class<?> clazz, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> headers, final OutputStream os)
+ throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.writeWithEntityProvider(): entry");
+ }
+ final long writerSize = writer.getSize(responseObject, clazz, type,
+ annotations, mediaType);
+ writer.writeTo(responseObject, clazz, type, annotations, mediaType,
+ headers, new ServletStatusOutputStream(context, headers, os,
+ writerSize, mediaType));
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.writeWithEntityProvider(): exit");
+ }
+ }
+
+ /**
+ * Called after the response has been written to the OutputStream. This method will
+ * flush the buffer on the servlet response.
+ */
+ public void postWrite(RESTContext context) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("ServletResponseWriter.postWrite(): entry");
+ }
+
+ HttpServletResponse servletResponse = (HttpServletResponse) context
+ .getProperty(ContextConstants.SERVLET_RESPONSE);
+
+ if (servletResponse == null) {
+ throw new IllegalArgumentException(Messages
+ .getMessage("servletResponseNotAvailable"));
+ }
+
+ /*
+ * check if the headers were already written. if they were, do not repeat headers.
+ * there is a possibility that there was no entity written so the status
+ * and headers need to be written here.
+ */
+ Boolean isStatusAndHeadersAlreadyWritten = (Boolean) context
+ .getProperty(ContextConstants.IS_HTTP_RESPONSE_STATUS_AND_HEADERS_WRITTEN);
+ if (!servletResponse.isCommitted()
+ && ((isStatusAndHeadersAlreadyWritten == null) || (!isStatusAndHeadersAlreadyWritten
+ .booleanValue()))) {
+ setStatusAndHeaders(context);
+
+ Integer length = ((Integer) context
+ .getProperty(ContextConstants.RESPONSE_CONTENT_LENGTH));
+ if (length == null) {
+ length = Integer.valueOf(0);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Setting Content-Length header on servlet response: "
+ + length);
+ }
+ servletResponse.setContentLength(length.intValue());
+ }
+
+ OutputStream os = (OutputStream) context
+ .getProperty(ContextConstants.RESPONSE_OUTPUT_STREAM);
+ os.flush();
+ servletResponse.flushBuffer();
+
+ // check to see if we should log what was written to the output stream
+ if (log.isDebugEnabled()) {
+ LogOutputStream los = (LogOutputStream) context
+ .getProperty(ContextConstants.OUTPUT_LOGGER);
+ if (los != null) {
+ los.logBytes();
+ }
+ log.debug("ServletResponseWriter.postWrite(): exit");
+ }
+ }
+
+ static void setStatusAndHeaders(RESTContext context) {
+ Response response = (Response) context
+ .getProperty(ContextConstants.RESPONSE);
+ if (response == null) {
+ throw new IllegalArgumentException(Messages
+ .getMessage("responseNotAvailable"));
+ }
+
+ MultivaluedMap<String, Object> rspHeaders = response.getMetadata();
+ HttpServletResponse servletResponse = (HttpServletResponse) context
+ .getProperty(ContextConstants.SERVLET_RESPONSE);
+
+ if (servletResponse == null) {
+ throw new IllegalArgumentException((Messages
+ .getMessage("servletResponseNotAvailable")));
+ }
+
+ String varyHeader = (String) context
+ .getProperty(ContextConstants.VARY_HEADER);
+ if (rspHeaders != null && rspHeaders.getFirst("vary") == null
+ && varyHeader != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Setting Vary header on servlet response: "
+ + varyHeader);
+ }
+ rspHeaders.putSingle("vary", varyHeader);
+ }
+
+ // add all the present headers
+ if (rspHeaders != null && !rspHeaders.isEmpty()) {
+ Iterator<String> keys = rspHeaders.keySet().iterator();
+ while (keys.hasNext()) {
+ String id = keys.next();
+ List<Object> values = response.getMetadata().get(id);
+ if (values != null && !values.isEmpty()) {
+ for (Object value : values) {
+ if (log.isDebugEnabled()) {
+ log.debug("Adding value: " + value.toString()
+ + " for id: " + id
+ + " to HTTP response header");
+ }
+ servletResponse.addHeader(id, value.toString());
+ }
+ }
+
+ }
+ }
+
+ // now let's set the status
+ int status = response.getStatus();
+ if (status == -1) {
+ servletResponse.setStatus((response.getEntity() == null) ? 204
+ : 200);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Setting response status to: " + status
+ + " from Response instance");
+ }
+ servletResponse.setStatus(status);
+ }
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletStatusOutputStream.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletStatusOutputStream.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletStatusOutputStream.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/ServletStatusOutputStream.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,133 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.ibm.ws.jaxrs.context.ContextConstants;
+import com.ibm.ws.jaxrs.context.RESTContext;
+
+/**
+ * Delegates to an underlying OutputStream for all operations, but if any write
+ * is done, be sure to write the status code and headers in case an underlying
+ * buffer is flushed.
+ */
+class ServletStatusOutputStream extends OutputStream {
+
+ private static final Log log = LogFactory
+ .getLog(ServletResponseWriter.class);
+
+ public ServletStatusOutputStream(RESTContext context, MultivaluedMap<String, Object> headers, OutputStream os, long writerSize, MediaType mt) {
+ this(context, headers, os, writerSize, mt.getType() + "/"
+ + mt.getSubtype());
+ }
+
+ public ServletStatusOutputStream(RESTContext context, MultivaluedMap<String, Object> headers, OutputStream os, long writerSize, String contentType) {
+ this.context = context;
+ this.headers = headers;
+ this.osDelegate = os;
+ this.writerSize = writerSize;
+ this.contentType = contentType;
+ }
+
+ final private RESTContext context;
+
+ /*
+ * all keys should be lower cased
+ */
+ final private MultivaluedMap<String, Object> headers;
+
+ final private OutputStream osDelegate;
+
+ final private long writerSize;
+
+ private boolean isFirstWrite = true;
+
+ final private String contentType;
+
+ final private void checkFirstWrite() {
+ /*
+ * write the headers once the body is started to be written. no chance
+ * to do it later if the body becomes huge. the headers must be changed
+ * already by the writer.
+ */
+ if (isFirstWrite) {
+ if (writerSize >= 0 && headers != null
+ && headers.getFirst("content-length") == null) {
+ if (log.isDebugEnabled()) {
+ log
+ .debug("Setting Content-Length header on servlet response: "
+ + writerSize);
+ }
+ headers.putSingle("content-length", Long.valueOf(writerSize));
+ }
+ if (headers != null && headers.getFirst("content-type") == null
+ && contentType != null) {
+ if (log.isDebugEnabled()) {
+ log
+ .debug("Setting Content-Type header on servlet response: "
+ + contentType);
+ }
+ headers.putSingle("content-type", contentType);
+ }
+ ServletResponseWriter.setStatusAndHeaders(context);
+ context
+ .setProperty(
+ ContextConstants.IS_HTTP_RESPONSE_STATUS_AND_HEADERS_WRITTEN,
+ Boolean.TRUE);
+ isFirstWrite = false;
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ checkFirstWrite();
+ osDelegate.write(b);
+ }
+
+ @Override
+ public void close() throws IOException {
+ osDelegate.close();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ osDelegate.flush();
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ checkFirstWrite();
+ osDelegate.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ checkFirstWrite();
+ osDelegate.write(b, off, len);
+ }
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationData.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationData.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationData.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationData.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,63 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web.asm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is a bean class that will be populated during the byte code
+ * scanning of an application. It will hold the necessary metadata
+ * for any JAX-RS resources or providers found in the application.
+ *
+ */
+public class JAXRSAnnotationData {
+
+ private List<String> resourceNames;
+
+ private List<String> providerNames;
+
+ public JAXRSAnnotationData() {
+ resourceNames = new ArrayList<String>();
+ providerNames = new ArrayList<String>();
+ }
+
+ public List<String> getResourceNames() {
+ return resourceNames;
+ }
+
+ public List<String> getProviderNames() {
+ return providerNames;
+ }
+
+ public List<String> getJAXRSNames() {
+ resourceNames.addAll(providerNames);
+ return resourceNames;
+ }
+
+ public void addResourceName(String name) {
+ resourceNames.add(name);
+ }
+
+ public void addProviderName(String name) {
+ providerNames.add(name);
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationScanner.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationScanner.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationScanner.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationScanner.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,71 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web.asm;
+
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+import com.ibm.ws.jaxrs.integration.DefaultApplication;
+import com.ibm.ws.jaxrs.utils.ClassUtils;
+
+/**
+ * This class will be the driver of our integration components with
+ * the ASM byte code scanning framework. It will drive the annotation
+ * scans to discover JAX-RS annotation metadata within a set of classes.
+ *
+ */
+public class JAXRSAnnotationScanner {
+
+ /**
+ * This method accepts a list of InputStream objects. Each InputStream
+ * represents the stream to a .class file. The byte code of the class
+ * will be scanned, and an Application instance will be returned that
+ * contains all JAX-RS resources and providers. Null will be returned
+ * if no JAX-RS classes were found.
+ */
+ public Application scan(List<InputStream> classInputs, ClassLoader classLoader)
+ throws Exception {
+ JAXRSAnnotationData jaxrsAnnotData = new JAXRSAnnotationData();
+ if (classInputs != null) {
+ for (InputStream classInput : classInputs) {
+ ClassReader reader = new ClassReader(classInput);
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ JAXRSClassAdapter adapter = new JAXRSClassAdapter(cw,
+ jaxrsAnnotData);
+ reader.accept(adapter, ClassReader.SKIP_DEBUG);
+ }
+ }
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ if (jaxrsAnnotData.getJAXRSNames() != null) {
+ for (String className : jaxrsAnnotData.getJAXRSNames()) {
+ classes.add(ClassUtils.loadClass(className, classLoader));
+ }
+ }
+ return new DefaultApplication(classes, null);
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationVisitor.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationVisitor.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationVisitor.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSAnnotationVisitor.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,60 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web.asm;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+ * This class implements the AnnotationVisitor interface in ASM, and
+ * it will be used to determine if a given class file contains the
+ * @Path or @Provider annotations.
+ *
+ */
+public class JAXRSAnnotationVisitor implements AnnotationVisitor {
+
+ /*
+ * Called to process the annotation.
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ // nothing to do here for now
+ return null;
+ }
+
+ public AnnotationVisitor visitArray(String arg0) {
+ // nothing to do here for now
+ return null;
+ }
+
+ public void visitEnum(String arg0, String arg1, String arg2) {
+ // nothing to do here for now
+ }
+
+ public void visitEnd() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
Added: incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSClassAdapter.java
URL: http://svn.apache.org/viewvc/incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSClassAdapter.java?rev=787557&view=auto
==============================================================================
--- incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSClassAdapter.java (added)
+++ incubator/wink/contrib/ibm-jaxrs/src/com/ibm/ws/jaxrs/web/asm/JAXRSClassAdapter.java Tue Jun 23 05:41:49 2009
@@ -0,0 +1,77 @@
+/*
+ * 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 com.ibm.ws.jaxrs.web.asm;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * This class will be a main integration point with the ASM framework.
+ * It will allow for byte-code scanning of class file contents, and we
+ * will use the results to determine the set of 'interesting' classes
+ * from a JAX-RS point of view.
+ *
+ */
+public class JAXRSClassAdapter extends ClassAdapter {
+
+ private static final Log log = LogFactory.getLog(JAXRSClassAdapter.class);
+
+ private static final String PATH_INTERNAL_NAME = "Ljavax/ws/rs/Path;";
+
+ private static final String PROVIDER_INTERNAL_NAME = "Ljavax/ws/rs/ext/Provider;";
+
+ private String className;
+
+ private JAXRSAnnotationData jaxrsAnnotData;
+
+ public JAXRSClassAdapter(ClassVisitor visitor, JAXRSAnnotationData jaxrsAnnotData) {
+ super(visitor);
+ this.jaxrsAnnotData = jaxrsAnnotData;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ className = name.replace("/", ".");
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String annotInternalName, boolean visible) {
+ if (PATH_INTERNAL_NAME.equals(annotInternalName)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Found the @Path annotation in the class: "
+ + className);
+ }
+ jaxrsAnnotData.addResourceName(className);
+ }
+ if (PROVIDER_INTERNAL_NAME.equals(annotInternalName)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Found the @Provider annotation in the class: "
+ + className);
+ }
+ jaxrsAnnotData.addResourceName(className);
+ }
+ return new EmptyVisitor();
+ }
+
+}
|