incubator-wink-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ngalla...@apache.org
Subject svn commit: r787557 [7/12] - in /incubator/wink/contrib/ibm-jaxrs: ./ lib/ src/ src/com/ src/com/ibm/ src/com/ibm/ws/ src/com/ibm/ws/jaxrs/ src/com/ibm/ws/jaxrs/annotations/ src/com/ibm/ws/jaxrs/context/ src/com/ibm/ws/jaxrs/core/ src/com/ibm/ws/jaxrs/...
Date Tue, 23 Jun 2009 05:41:55 GMT
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();
+    }
+
+}



Mime
View raw message