public final class ResourceUtils { private static final Logger LOG = LogUtils.getL7dLogger(ResourceUtils.class); private static final ResourceBundle BUNDLE = BundleUtils.getBundle(ResourceUtils.class); private static final String CLASSPATH_PREFIX = "classpath:"; private static final Set<String> SERVER_PROVIDER_CLASS_NAMES; static { SERVER_PROVIDER_CLASS_NAMES = new HashSet<String>(); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.MessageBodyWriter"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.MessageBodyReader"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.ExceptionMapper"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.ContextResolver"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.ReaderInterceptor"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.WriterInterceptor"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.ext.ParamConverterProvider"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.container.ContainerRequestFilter"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.container.ContainerResponseFilter"); SERVER_PROVIDER_CLASS_NAMES.add("javax.ws.rs.container.DynamicFeature"); SERVER_PROVIDER_CLASS_NAMES.add("org.apache.cxf.jaxrs.ext.ContextResolver"); } private ResourceUtils() {} public static Method findPostConstructMethod(Class<?> c) { return findPostConstructMethod(c, null); } public static Method findPostConstructMethod(Class<?> c, String name) { if (Object.class == c || null == c) { return null; } for (Method m : c.getDeclaredMethods()) { if (name != null) { if (m.getName().equals(name)) { return m; } } else if (m.getAnnotation(PostConstruct.class) != null) { return m; } } Method m = findPostConstructMethod(c.getSuperclass(), name); if (m != null) { return m; } for (Class<?> i : c.getInterfaces()) { m = findPostConstructMethod(i, name); if (m != null) { return m; } } return null; } public static Method findPreDestroyMethod(Class<?> c) { return findPreDestroyMethod(c, null); } public static Method findPreDestroyMethod(Class<?> c, String name) { if (Object.class == c || null == c) { return null; } for (Method m : c.getDeclaredMethods()) { if (name != null) { if (m.getName().equals(name)) { return m; } } else if (m.getAnnotation(PreDestroy.class) != null) { return m; } } Method m = findPreDestroyMethod(c.getSuperclass(), name); if (m != null) { return m; } for (Class<?> i : c.getInterfaces()) { m = findPreDestroyMethod(i, name); if (m != null) { return m; } } return null; } public static ClassResourceInfo createClassResourceInfo( Map<String, UserResource> resources, UserResource model, Class<?> defaultClass, boolean isRoot, boolean enableStatic, Bus bus) { final boolean isDefaultClass = defaultClass != null; Class<?> sClass = !isDefaultClass ? loadClass(model.getName()) : defaultClass; return createServiceClassResourceInfo(resources, model, sClass, isRoot, enableStatic, bus); } public static ClassResourceInfo createServiceClassResourceInfo( Map<String, UserResource> resources, UserResource model, Class<?> sClass, boolean isRoot, boolean enableStatic, Bus bus) { if (model == null) { throw new RuntimeException("Resource class " + sClass.getName() + " has no model info"); } ClassResourceInfo cri = new ClassResourceInfo( sClass, sClass, isRoot, enableStatic, true, model.getConsumes(), model.getProduces(), bus); URITemplate t = URITemplate.createTemplate(model.getPath()); cri.setURITemplate(t); MethodDispatcher md = new MethodDispatcher(); Map<String, UserOperation> ops = model.getOperationsAsMap(); Method defaultMethod = null; Map<String, Method> methodNames = new HashMap<String, Method>(); for (Method m : cri.getServiceClass().getMethods()) { if (m.getAnnotation(DefaultMethod.class) != null) { // if needed we can also support multiple default methods defaultMethod = m; } methodNames.put(m.getName(), m); } for (Map.Entry<String, UserOperation> entry : ops.entrySet()) { UserOperation op = entry.getValue(); Method actualMethod = methodNames.get(op.getName()); if (actualMethod == null) { actualMethod = defaultMethod; } if (actualMethod == null) { continue; } OperationResourceInfo ori = new OperationResourceInfo( actualMethod, cri, URITemplate.createTemplate(op.getPath()), op.getVerb(), op.getConsumes(), op.getProduces(), op.getParameters(), op.isOneway()); String rClassName = actualMethod.getReturnType().getName(); if (op.getVerb() == null) { if (resources.containsKey(rClassName)) { ClassResourceInfo subCri = rClassName.equals(model.getName()) ? cri : createServiceClassResourceInfo( resources, resources.get(rClassName), actualMethod.getReturnType(), false, enableStatic, bus); if (subCri != null) { cri.addSubClassResourceInfo(subCri); md.bind(ori, actualMethod); } } } else { md.bind(ori, actualMethod); } } cri.setMethodDispatcher(md); return checkMethodDispatcher(cri) ? cri : null; } public static ClassResourceInfo createClassResourceInfo( final Class<?> rClass, final Class<?> sClass, boolean root, boolean enableStatic) { return createClassResourceInfo( rClass, sClass, root, enableStatic, BusFactory.getThreadDefaultBus()); } public static ClassResourceInfo createClassResourceInfo( final Class<?> rClass, final Class<?> sClass, boolean root, boolean enableStatic, Bus bus) { return createClassResourceInfo(rClass, sClass, null, root, enableStatic, bus); } public static ClassResourceInfo createClassResourceInfo( final Class<?> rClass, final Class<?> sClass, ClassResourceInfo parent, boolean root, boolean enableStatic, Bus bus) { ClassResourceInfo cri = new ClassResourceInfo(rClass, sClass, root, enableStatic, bus); cri.setParent(parent); if (root) { URITemplate t = URITemplate.createTemplate(cri.getPath()); cri.setURITemplate(t); } evaluateResourceClass(cri, enableStatic); return checkMethodDispatcher(cri) ? cri : null; } private static void evaluateResourceClass(ClassResourceInfo cri, boolean enableStatic) { MethodDispatcher md = new MethodDispatcher(); Class<?> serviceClass = cri.getServiceClass(); boolean isFineLevelLoggable = LOG.isLoggable(Level.FINE); for (Method m : serviceClass.getMethods()) { Method annotatedMethod = AnnotationUtils.getAnnotatedMethod(serviceClass, m); String httpMethod = AnnotationUtils.getHttpMethodValue(annotatedMethod); Path path = AnnotationUtils.getMethodAnnotation(annotatedMethod, Path.class); if (httpMethod != null || path != null) { md.bind(createOperationInfo(m, annotatedMethod, cri, path, httpMethod), m); if (httpMethod == null) { // subresource locator Class<?> subClass = m.getReturnType(); if (enableStatic) { ClassResourceInfo subCri = cri.findResource(subClass, subClass); if (subCri == null) { ClassResourceInfo ancestor = getAncestorWithSameServiceClass(cri, subClass); subCri = ancestor != null ? ancestor : createClassResourceInfo( subClass, subClass, cri, false, enableStatic, cri.getBus()); } if (subCri != null) { cri.addSubClassResourceInfo(subCri); } } } } else if (isFineLevelLoggable) { LOG.fine( new org.apache.cxf.common.i18n.Message( "NOT_RESOURCE_METHOD", BUNDLE, m.getDeclaringClass().getName(), m.getName()) .toString()); } } cri.setMethodDispatcher(md); } private static ClassResourceInfo getAncestorWithSameServiceClass( ClassResourceInfo parent, Class<?> subClass) { if (parent == null) { return null; } if (parent.getServiceClass() == subClass) { return parent; } return getAncestorWithSameServiceClass(parent.getParent(), subClass); } public static Constructor<?> findResourceConstructor(Class<?> resourceClass, boolean perRequest) { List<Constructor<?>> cs = new LinkedList<Constructor<?>>(); for (Constructor<?> c : resourceClass.getConstructors()) { Class<?>[] params = c.getParameterTypes(); Annotation[][] anns = c.getParameterAnnotations(); boolean match = true; for (int i = 0; i < params.length; i++) { if (!perRequest) { if (AnnotationUtils.getAnnotation(anns[i], Context.class) == null) { match = false; break; } } else if (!AnnotationUtils.isValidParamAnnotations(anns[i])) { match = false; break; } } if (match) { cs.add(c); } } Collections.sort( cs, new Comparator<Constructor<?>>() { public int compare(Constructor<?> c1, Constructor<?> c2) { int p1 = c1.getParameterTypes().length; int p2 = c2.getParameterTypes().length; return p1 > p2 ? -1 : p1 < p2 ? 1 : 0; } }); return cs.size() == 0 ? null : cs.get(0); } public static List<Parameter> getParameters(Method resourceMethod) { Annotation[][] paramAnns = resourceMethod.getParameterAnnotations(); if (paramAnns.length == 0) { return CastUtils.cast(Collections.emptyList(), Parameter.class); } Class<?>[] types = resourceMethod.getParameterTypes(); List<Parameter> params = new ArrayList<Parameter>(paramAnns.length); for (int i = 0; i < paramAnns.length; i++) { Parameter p = getParameter(i, paramAnns[i], types[i]); params.add(p); } return params; } // CHECKSTYLE:OFF public static Parameter getParameter(int index, Annotation[] anns, Class<?> type) { Context ctx = AnnotationUtils.getAnnotation(anns, Context.class); if (ctx != null) { return new Parameter(ParameterType.CONTEXT, index, null); } boolean isEncoded = AnnotationUtils.getAnnotation(anns, Encoded.class) != null; BeanParam bp = AnnotationUtils.getAnnotation(anns, BeanParam.class); if (bp != null) { return new Parameter(ParameterType.BEAN, index, null, isEncoded, null); } String dValue = AnnotationUtils.getDefaultParameterValue(anns); PathParam a = AnnotationUtils.getAnnotation(anns, PathParam.class); if (a != null) { return new Parameter(ParameterType.PATH, index, a.value(), isEncoded, dValue); } QueryParam q = AnnotationUtils.getAnnotation(anns, QueryParam.class); if (q != null) { return new Parameter(ParameterType.QUERY, index, q.value(), isEncoded, dValue); } MatrixParam m = AnnotationUtils.getAnnotation(anns, MatrixParam.class); if (m != null) { return new Parameter(ParameterType.MATRIX, index, m.value(), isEncoded, dValue); } FormParam f = AnnotationUtils.getAnnotation(anns, FormParam.class); if (f != null) { return new Parameter(ParameterType.FORM, index, f.value(), isEncoded, dValue); } HeaderParam h = AnnotationUtils.getAnnotation(anns, HeaderParam.class); if (h != null) { return new Parameter(ParameterType.HEADER, index, h.value(), isEncoded, dValue); } CookieParam c = AnnotationUtils.getAnnotation(anns, CookieParam.class); if (c != null) { return new Parameter(ParameterType.COOKIE, index, c.value(), isEncoded, dValue); } return new Parameter(ParameterType.REQUEST_BODY, index, null); } // CHECKSTYLE:ON private static OperationResourceInfo createOperationInfo( Method m, Method annotatedMethod, ClassResourceInfo cri, Path path, String httpMethod) { OperationResourceInfo ori = new OperationResourceInfo(m, annotatedMethod, cri); URITemplate t = URITemplate.createTemplate(path); ori.setURITemplate(t); ori.setHttpMethod(httpMethod); return ori; } private static boolean checkMethodDispatcher(ClassResourceInfo cr) { if (cr.getMethodDispatcher().getOperationResourceInfos().isEmpty()) { LOG.warning( new org.apache.cxf.common.i18n.Message( "NO_RESOURCE_OP_EXC", BUNDLE, cr.getServiceClass().getName()) .toString()); return false; } return true; } private static Class<?> loadClass(String cName) { try { return ClassLoaderUtils.loadClass(cName.trim(), ResourceUtils.class); } catch (ClassNotFoundException ex) { throw new RuntimeException("No class " + cName.trim() + " can be found", ex); } } public static List<UserResource> getUserResources(String loc, Bus bus) { try { InputStream is = ResourceUtils.getResourceStream(loc, bus); if (is == null) { return null; } return getUserResources(is); } catch (Exception ex) { LOG.warning("Problem with processing a user model at " + loc); } return null; } public static InputStream getResourceStream(String loc, Bus bus) throws Exception { URL url = getResourceURL(loc, bus); return url == null ? null : url.openStream(); } public static URL getResourceURL(String loc, Bus bus) throws Exception { URL url = null; if (loc.startsWith(CLASSPATH_PREFIX)) { String path = loc.substring(CLASSPATH_PREFIX.length()); url = ResourceUtils.getClasspathResourceURL(path, ResourceUtils.class, bus); } else { try { url = new URL(loc); } catch (Exception ex) { // it can be either a classpath or file resource without a scheme url = ResourceUtils.getClasspathResourceURL(loc, ResourceUtils.class, bus); if (url == null) { File file = new File(loc); if (file.exists()) { url = file.toURI().toURL(); } } } } if (url == null) { LOG.warning("No resource " + loc + " is available"); } return url; } public static InputStream getClasspathResourceStream( String path, Class<?> callingClass, Bus bus) { InputStream is = ClassLoaderUtils.getResourceAsStream(path, callingClass); return is == null ? getResource(path, InputStream.class, bus) : is; } public static URL getClasspathResourceURL(String path, Class<?> callingClass, Bus bus) { URL url = ClassLoaderUtils.getResource(path, callingClass); return url == null ? getResource(path, URL.class, bus) : url; } public static <T> T getResource(String path, Class<T> resourceClass, Bus bus) { if (bus != null) { ResourceManager rm = bus.getExtension(ResourceManager.class); if (rm != null) { return rm.resolveResource(path, resourceClass); } } return null; } public static Properties loadProperties(String propertiesLocation, Bus bus) throws Exception { Properties props = new Properties(); InputStream is = getResourceStream(propertiesLocation, bus); props.load(is); return props; } public static List<UserResource> getUserResources(String loc) { return getUserResources(loc, BusFactory.getThreadDefaultBus()); } public static List<UserResource> getUserResources(InputStream is) throws Exception { Document doc = StaxUtils.read(new InputStreamReader(is, "UTF-8")); return getResourcesFromElement(doc.getDocumentElement()); } public static List<UserResource> getResourcesFromElement(Element modelEl) { List<UserResource> resources = new ArrayList<UserResource>(); List<Element> resourceEls = DOMUtils.findAllElementsByTagNameNS(modelEl, "http://cxf.apache.org/jaxrs", "resource"); for (Element e : resourceEls) { resources.add(getResourceFromElement(e)); } return resources; } public static ResourceTypes getAllRequestResponseTypes( List<ClassResourceInfo> cris, boolean jaxbOnly) { return getAllRequestResponseTypes(cris, jaxbOnly, null); } public static ResourceTypes getAllRequestResponseTypes( List<ClassResourceInfo> cris, boolean jaxbOnly, MessageBodyWriter<?> jaxbWriter) { ResourceTypes types = new ResourceTypes(); for (ClassResourceInfo resource : cris) { getAllTypesForResource(resource, types, jaxbOnly, jaxbWriter); } return types; } public static Class<?> getActualJaxbType(Class<?> type, Method resourceMethod, boolean inbound) { ElementClass element = resourceMethod.getAnnotation(ElementClass.class); if (element != null) { Class<?> cls = inbound ? element.request() : element.response(); if (cls != Object.class) { return cls; } } return type; } private static void getAllTypesForResource( ClassResourceInfo resource, ResourceTypes types, boolean jaxbOnly, MessageBodyWriter<?> jaxbWriter) { for (OperationResourceInfo ori : resource.getMethodDispatcher().getOperationResourceInfos()) { Method method = ori.getMethodToInvoke(); Class<?> realReturnType = method.getReturnType(); Class<?> cls = realReturnType; if (cls == Response.class) { cls = getActualJaxbType(cls, method, false); } Type type = method.getGenericReturnType(); if (jaxbOnly) { checkJaxbType( resource.getServiceClass(), cls, realReturnType == Response.class ? cls : type, types, method.getAnnotations(), jaxbWriter); } else { types.getAllTypes().put(cls, type); } for (Parameter pm : ori.getParameters()) { if (pm.getType() == ParameterType.REQUEST_BODY) { Class<?> inType = method.getParameterTypes()[pm.getIndex()]; Type paramType = method.getGenericParameterTypes()[pm.getIndex()]; if (jaxbOnly) { checkJaxbType( resource.getServiceClass(), inType, paramType, types, method.getParameterAnnotations()[pm.getIndex()], jaxbWriter); } else { types.getAllTypes().put(inType, paramType); } } } } for (ClassResourceInfo sub : resource.getSubResources()) { if (!isRecursiveSubResource(resource, sub)) { getAllTypesForResource(sub, types, jaxbOnly, jaxbWriter); } } } private static boolean isRecursiveSubResource(ClassResourceInfo parent, ClassResourceInfo sub) { if (parent == null) { return false; } if (parent == sub) { return true; } return isRecursiveSubResource(parent.getParent(), sub); } private static void checkJaxbType( Class<?> serviceClass, Class<?> type, Type genericType, ResourceTypes types, Annotation[] anns, MessageBodyWriter<?> jaxbWriter) { boolean isCollection = false; if (InjectionUtils.isSupportedCollectionOrArray(type)) { type = InjectionUtils.getActualType(genericType); isCollection = true; } if (type == Object.class && !(genericType instanceof Class)) { Type theType = InjectionUtils.processGenericTypeIfNeeded(serviceClass, Object.class, genericType); type = InjectionUtils.getActualType(theType); } if (type == null || InjectionUtils.isPrimitive(type) || JAXBElement.class.isAssignableFrom(type) || Response.class.isAssignableFrom(type) || type.isInterface()) { return; } MessageBodyWriter<?> writer = jaxbWriter; if (writer == null) { JAXBElementProvider<Object> defaultWriter = new JAXBElementProvider<Object>(); defaultWriter.setMarshallAsJaxbElement(true); defaultWriter.setXmlTypeAsJaxbElementOnly(true); writer = defaultWriter; } if (writer.isWriteable(type, type, anns, MediaType.APPLICATION_XML_TYPE)) { types.getAllTypes().put(type, type); Class<?> genCls = InjectionUtils.getActualType(genericType); if (genCls != type && genCls != null && genCls != Object.class && !InjectionUtils.isSupportedCollectionOrArray(genCls)) { types.getAllTypes().put(genCls, genCls); } XMLName name = AnnotationUtils.getAnnotation(anns, XMLName.class); QName qname = name != null ? JAXRSUtils.convertStringToQName(name.value()) : null; if (isCollection) { types.getCollectionMap().put(type, qname); } else { types.getXmlNameMap().put(type, qname); } } } private static UserResource getResourceFromElement(Element e) { UserResource resource = new UserResource(); resource.setName(e.getAttribute("name")); resource.setPath(e.getAttribute("path")); resource.setConsumes(e.getAttribute("consumes")); resource.setProduces(e.getAttribute("produces")); List<Element> operEls = DOMUtils.findAllElementsByTagNameNS(e, "http://cxf.apache.org/jaxrs", "operation"); List<UserOperation> opers = new ArrayList<UserOperation>(operEls.size()); for (Element operEl : operEls) { opers.add(getOperationFromElement(operEl)); } resource.setOperations(opers); return resource; } private static UserOperation getOperationFromElement(Element e) { UserOperation op = new UserOperation(); op.setName(e.getAttribute("name")); op.setVerb(e.getAttribute("verb")); op.setPath(e.getAttribute("path")); op.setOneway(Boolean.parseBoolean(e.getAttribute("oneway"))); op.setConsumes(e.getAttribute("consumes")); op.setProduces(e.getAttribute("produces")); List<Element> paramEls = DOMUtils.findAllElementsByTagNameNS(e, "http://cxf.apache.org/jaxrs", "param"); List<Parameter> params = new ArrayList<Parameter>(paramEls.size()); for (int i = 0; i < paramEls.size(); i++) { Element paramEl = paramEls.get(i); Parameter p = new Parameter(paramEl.getAttribute("type"), i, paramEl.getAttribute("name")); p.setEncoded(Boolean.valueOf(paramEl.getAttribute("encoded"))); p.setDefaultValue(paramEl.getAttribute("defaultValue")); String pClass = paramEl.getAttribute("class"); if (!StringUtils.isEmpty(pClass)) { try { p.setJavaType(ClassLoaderUtils.loadClass(pClass, ResourceUtils.class)); } catch (Exception ex) { throw new RuntimeException(ex); } } params.add(p); } op.setParameters(params); return op; } public static Object[] createConstructorArguments( Constructor<?> c, Message m, boolean perRequest) { return createConstructorArguments(c, m, perRequest, null); } public static Object[] createConstructorArguments( Constructor<?> c, Message m, boolean perRequest, Map<Class<?>, Object> contextValues) { Class<?>[] params = c.getParameterTypes(); Annotation[][] anns = c.getParameterAnnotations(); Type[] genericTypes = c.getGenericParameterTypes(); @SuppressWarnings("unchecked") MultivaluedMap<String, String> templateValues = m == null ? null : (MultivaluedMap<String, String>) m.get(URITemplate.TEMPLATE_PARAMETERS); Object[] values = new Object[params.length]; for (int i = 0; i < params.length; i++) { if (AnnotationUtils.getAnnotation(anns[i], Context.class) != null) { Object contextValue = contextValues != null ? contextValues.get(params[i]) : null; if (contextValue == null) { if (perRequest) { values[i] = JAXRSUtils.createContextValue(m, genericTypes[i], params[i]); } else { values[i] = InjectionUtils.createThreadLocalProxy(params[i]); } } else { values[i] = contextValue; } } else { // this branch won't execute for singletons given that the found constructor // is guaranteed to have only Context parameters, if any, for singletons Parameter p = ResourceUtils.getParameter(i, anns[i], params[i]); values[i] = JAXRSUtils.createHttpParameterValue( p, params[i], genericTypes[i], anns[i], m, templateValues, null); } } return values; } public static JAXRSServerFactoryBean createApplication(Application app, boolean ignoreAppPath) { return createApplication(app, ignoreAppPath, false); } @SuppressWarnings("unchecked") public static JAXRSServerFactoryBean createApplication( Application app, boolean ignoreAppPath, boolean staticSubresourceResolution) { Set<Object> singletons = app.getSingletons(); verifySingletons(singletons); List<Class<?>> resourceClasses = new ArrayList<Class<?>>(); List<Object> providers = new ArrayList<Object>(); List<Feature> features = new ArrayList<Feature>(); Map<Class<?>, ResourceProvider> map = new HashMap<Class<?>, ResourceProvider>(); // Note, app.getClasses() returns a list of per-request classes // or singleton provider classes for (Class<?> cls : app.getClasses()) { if (isValidApplicationClass(cls, singletons)) { if (isValidProvider(cls)) { providers.add(createProviderInstance(cls)); } else if (Feature.class.isAssignableFrom(cls)) { features.add(createFeatureInstance((Class<? extends Feature>) cls)); } else { resourceClasses.add(cls); map.put(cls, new PerRequestResourceProvider(cls)); } } } // we can get either a provider or resource class here for (Object o : singletons) { if (isValidProvider(o.getClass())) { providers.add(o); } else if (o instanceof Feature) { features.add((Feature) o); } else { resourceClasses.add(o.getClass()); map.put(o.getClass(), new SingletonResourceProvider(o)); } } JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean(); String address = "/"; if (!ignoreAppPath) { ApplicationPath appPath = app.getClass().getAnnotation(ApplicationPath.class); if (appPath != null) { address = appPath.value(); } } if (!address.startsWith("/")) { address = "/" + address; } bean.setAddress(address); bean.setStaticSubresourceResolution(staticSubresourceResolution); bean.setResourceClasses(resourceClasses); bean.setProviders(providers); bean.setFeatures(features); for (Map.Entry<Class<?>, ResourceProvider> entry : map.entrySet()) { bean.setResourceProvider(entry.getKey(), entry.getValue()); } Map<String, Object> appProps = app.getProperties(); if (appProps != null) { bean.getProperties(true).putAll(appProps); } bean.setApplication(app); return bean; } public static Object createProviderInstance(Class<?> cls) { try { Constructor<?> c = ResourceUtils.findResourceConstructor(cls, false); if (c.getParameterTypes().length == 0) { return c.newInstance(); } else { return c; } } catch (Throwable ex) { throw new RuntimeException("Provider " + cls.getName() + " can not be created", ex); } } public static Feature createFeatureInstance(Class<? extends Feature> cls) { try { Constructor<?> c = ResourceUtils.findResourceConstructor(cls, false); if (c == null) { throw new RuntimeException("No valid constructor found for " + cls.getName()); } return (Feature) c.newInstance(); } catch (Throwable ex) { throw new RuntimeException("Feature " + cls.getName() + " can not be created", ex); } } private static boolean isValidProvider(Class<?> c) { if (c == null || c == Object.class) { return false; } if (c.getAnnotation(Provider.class) != null) { return true; } for (Class<?> itf : c.getInterfaces()) { if (SERVER_PROVIDER_CLASS_NAMES.contains(itf.getName())) { return true; } } return isValidProvider(c.getSuperclass()); } private static void verifySingletons(Set<Object> singletons) { if (singletons.isEmpty()) { return; } Set<String> map = new HashSet<String>(); for (Object s : singletons) { if (map.contains(s.getClass().getName())) { throw new RuntimeException( "More than one instance of the same singleton class " + s.getClass().getName() + " is available"); } else { map.add(s.getClass().getName()); } } } public static boolean isValidResourceClass(Class<?> c) { if (c.isInterface() || Modifier.isAbstract(c.getModifiers())) { LOG.info("Ignoring invalid resource class " + c.getName()); return false; } return true; } private static boolean isValidApplicationClass(Class<?> c, Set<Object> singletons) { if (!isValidResourceClass(c)) { return false; } for (Object s : singletons) { if (c == s.getClass()) { LOG.info( "Ignoring per-request resource class " + c.getName() + " as it is also registered as singleton"); return false; } } return true; } // TODO : consider moving JAXBDataBinding.createContext to JAXBUtils public static JAXBContext createJaxbContext( Set<Class<?>> classes, Class<?>[] extraClass, Map<String, Object> contextProperties) { if (classes == null || classes.isEmpty()) { return null; } JAXBUtils.scanPackages(classes, extraClass, null); JAXBContext ctx; try { ctx = JAXBContext.newInstance(classes.toArray(new Class[classes.size()]), contextProperties); return ctx; } catch (JAXBException ex) { LOG.log(Level.WARNING, "No JAXB context can be created", ex); } return null; } }
/** * Validate incoming MAPs * * @param maps the incoming MAPs * @param message the current message * @return true if incoming MAPs are valid * @pre inbound message, not requestor */ private boolean validateIncomingMAPs(AddressingProperties maps, Message message) { boolean valid = true; if (maps != null) { // WSAB spec, section 4.2 validation (SOAPAction must match action String sa = SoapActionInInterceptor.getSoapAction(message); String s1 = this.getActionUri(message, false); if (maps.getAction() == null || maps.getAction().getValue() == null) { String reason = BUNDLE.getString("MISSING_ACTION_MESSAGE"); ContextUtils.storeMAPFaultName(Names.HEADER_REQUIRED_NAME, message); ContextUtils.storeMAPFaultReason(reason, message); valid = false; } if (!StringUtils.isEmpty(sa) && valid && !MessageUtils.isTrue(message.get(MAPAggregator.ACTION_VERIFIED))) { if (sa.startsWith("\"")) { sa = sa.substring(1, sa.lastIndexOf('"')); } String action = maps.getAction() == null ? "" : maps.getAction().getValue(); if (!StringUtils.isEmpty(sa) && !sa.equals(action)) { // don't match, must send fault back.... String reason = BUNDLE.getString("INVALID_ADDRESSING_PROPERTY_MESSAGE"); ContextUtils.storeMAPFaultName(Names.ACTION_MISMATCH_NAME, message); ContextUtils.storeMAPFaultReason(reason, message); valid = false; } else if (!StringUtils.isEmpty(s1) && !action.equals(s1) && !action.equals(s1 + "Request") && !s1.equals(action + "Request")) { // if java first, it's likely to have "Request", if wsdl first, // it will depend if the wsdl:input has a name or not. Thus, we'll // check both plain and with the "Request" trailer // doesn't match what's in the wsdl/annotations String reason = BundleUtils.getFormattedString(BUNDLE, "ACTION_NOT_SUPPORTED_MSG", action); ContextUtils.storeMAPFaultName(Names.ACTION_NOT_SUPPORTED_NAME, message); ContextUtils.storeMAPFaultReason(reason, message); valid = false; } } AttributedURIType messageID = maps.getMessageID(); if (!message.getExchange().isOneWay() && (messageID == null || messageID.getValue() == null) && valid) { String reason = BUNDLE.getString("MISSING_ACTION_MESSAGE"); ContextUtils.storeMAPFaultName(Names.HEADER_REQUIRED_NAME, message); ContextUtils.storeMAPFaultReason(reason, message); valid = false; } // Always cache message IDs, even when the message is not valid for some // other reason. if (!allowDuplicates && messageID != null && messageID.getValue() != null && !messageIdCache.checkUniquenessAndCacheId(messageID.getValue())) { LOG.log(Level.WARNING, "DUPLICATE_MESSAGE_ID_MSG", messageID.getValue()); // Only throw the fault if something else has not already marked the // message as invalid. if (valid) { String reason = BUNDLE.getString("DUPLICATE_MESSAGE_ID_MSG"); String l7dReason = MessageFormat.format(reason, messageID.getValue()); ContextUtils.storeMAPFaultName(Names.DUPLICATE_MESSAGE_ID_NAME, message); ContextUtils.storeMAPFaultReason(l7dReason, message); } valid = false; } } else if (usingAddressingAdvisory) { String reason = BUNDLE.getString("MISSING_ACTION_MESSAGE"); ContextUtils.storeMAPFaultName(Names.HEADER_REQUIRED_NAME, message); ContextUtils.storeMAPFaultReason(reason, message); valid = false; } if (Names.INVALID_CARDINALITY_NAME.equals(ContextUtils.retrieveMAPFaultName(message))) { valid = false; } return valid; }
public class JAXRSOutInterceptor extends AbstractOutDatabindingInterceptor { private static final Logger LOG = LogUtils.getL7dLogger(JAXRSOutInterceptor.class); private static final ResourceBundle BUNDLE = BundleUtils.getBundle(JAXRSOutInterceptor.class); public JAXRSOutInterceptor() { super(Phase.MARSHAL); } public void handleMessage(Message message) { ServerProviderFactory providerFactory = ServerProviderFactory.getInstance(message); try { processResponse(providerFactory, message); } finally { ServerProviderFactory.releaseRequestState(providerFactory, message); } } private void processResponse(ServerProviderFactory providerFactory, Message message) { if (isResponseAlreadyHandled(message)) { return; } MessageContentsList objs = MessageContentsList.getContentsList(message); if (objs == null || objs.size() == 0) { return; } Object responseObj = objs.get(0); Response response = null; if (responseObj instanceof Response) { response = (Response) responseObj; if (response.getStatus() == 500 && message.getExchange().get(JAXRSUtils.EXCEPTION_FROM_MAPPER) != null) { message.put(Message.RESPONSE_CODE, 500); return; } } else { int status = getStatus(message, responseObj != null ? 200 : 204); response = JAXRSUtils.toResponseBuilder(status).entity(responseObj).build(); } Exchange exchange = message.getExchange(); OperationResourceInfo ori = (OperationResourceInfo) exchange.get(OperationResourceInfo.class.getName()); serializeMessage(providerFactory, message, response, ori, true); } private int getStatus(Message message, int defaultValue) { Object customStatus = message.getExchange().get(Message.RESPONSE_CODE); return customStatus == null ? defaultValue : (Integer) customStatus; } private void serializeMessage( ServerProviderFactory providerFactory, Message message, Response theResponse, OperationResourceInfo ori, boolean firstTry) { ResponseImpl response = (ResponseImpl) JAXRSUtils.copyResponseIfNeeded(theResponse); final Exchange exchange = message.getExchange(); boolean headResponse = response.getStatus() == 200 && firstTry && ori != null && HttpMethod.HEAD.equals(ori.getHttpMethod()); Object entity = response.getActualEntity(); if (headResponse && entity != null) { LOG.info(new org.apache.cxf.common.i18n.Message("HEAD_WITHOUT_ENTITY", BUNDLE).toString()); entity = null; } Method invoked = ori == null ? null : ori.getAnnotatedMethod() != null ? ori.getAnnotatedMethod() : ori.getMethodToInvoke(); Annotation[] annotations = null; Annotation[] staticAnns = ori != null ? ori.getOutAnnotations() : new Annotation[] {}; Annotation[] responseAnns = response.getEntityAnnotations(); if (responseAnns != null) { annotations = new Annotation[staticAnns.length + responseAnns.length]; System.arraycopy(staticAnns, 0, annotations, 0, staticAnns.length); System.arraycopy(responseAnns, 0, annotations, staticAnns.length, responseAnns.length); } else { annotations = staticAnns; } response.setStatus(getActualStatus(response.getStatus(), entity)); response.setEntity(entity, annotations); // Prepare the headers MultivaluedMap<String, Object> responseHeaders = prepareResponseHeaders(message, response, entity, firstTry); // Run the filters try { JAXRSUtils.runContainerResponseFilters(providerFactory, response, message, ori, invoked); } catch (Throwable ex) { handleWriteException(providerFactory, message, ex, firstTry); return; } // Write the entity entity = InjectionUtils.getEntity(response.getActualEntity()); setResponseStatus(message, getActualStatus(response.getStatus(), entity)); if (entity == null) { if (!headResponse) { responseHeaders.putSingle(HttpHeaders.CONTENT_LENGTH, "0"); if (MessageUtils.getContextualBoolean( message, "remove.content.type.for.empty.response", false)) { responseHeaders.remove(HttpHeaders.CONTENT_TYPE); message.remove(Message.CONTENT_TYPE); } } HttpUtils.convertHeaderValuesToString(responseHeaders, true); return; } Object ignoreWritersProp = exchange.get(JAXRSUtils.IGNORE_MESSAGE_WRITERS); boolean ignoreWriters = ignoreWritersProp == null ? false : Boolean.valueOf(ignoreWritersProp.toString()); if (ignoreWriters) { writeResponseToStream(message.getContent(OutputStream.class), entity); return; } MediaType responseMediaType = getResponseMediaType(responseHeaders.getFirst(HttpHeaders.CONTENT_TYPE)); Class<?> serviceCls = invoked != null ? ori.getClassResourceInfo().getServiceClass() : null; Class<?> targetType = InjectionUtils.getRawResponseClass(entity); Type genericType = InjectionUtils.getGenericResponseType( invoked, serviceCls, response.getActualEntity(), targetType, exchange); targetType = InjectionUtils.updateParamClassToTypeIfNeeded(targetType, genericType); annotations = response.getEntityAnnotations(); List<WriterInterceptor> writers = providerFactory.createMessageBodyWriterInterceptor( targetType, genericType, annotations, responseMediaType, message, ori == null ? null : ori.getNameBindings()); OutputStream outOriginal = message.getContent(OutputStream.class); if (writers == null || writers.isEmpty()) { writeResponseErrorMessage( message, outOriginal, "NO_MSG_WRITER", targetType, responseMediaType); return; } try { boolean checkWriters = false; if (responseMediaType.isWildcardSubtype()) { Produces pM = AnnotationUtils.getMethodAnnotation( ori == null ? null : ori.getAnnotatedMethod(), Produces.class); Produces pC = AnnotationUtils.getClassAnnotation(serviceCls, Produces.class); checkWriters = pM == null && pC == null; } responseMediaType = checkFinalContentType(responseMediaType, writers, checkWriters); } catch (Throwable ex) { handleWriteException(providerFactory, message, ex, firstTry); return; } String finalResponseContentType = JAXRSUtils.mediaTypeToString(responseMediaType); if (LOG.isLoggable(Level.FINE)) { LOG.fine("Response content type is: " + finalResponseContentType); } responseHeaders.putSingle(HttpHeaders.CONTENT_TYPE, finalResponseContentType); message.put(Message.CONTENT_TYPE, finalResponseContentType); boolean enabled = checkBufferingMode(message, writers, firstTry); try { try { JAXRSUtils.writeMessageBody( writers, entity, targetType, genericType, annotations, responseMediaType, responseHeaders, message); if (isResponseRedirected(message)) { return; } checkCachedStream(message, outOriginal, enabled); } finally { if (enabled) { OutputStream os = message.getContent(OutputStream.class); if (os != outOriginal && os instanceof CachedOutputStream) { os.close(); } message.setContent(OutputStream.class, outOriginal); message.put(XMLStreamWriter.class.getName(), null); } } } catch (Throwable ex) { logWriteError(firstTry, targetType, responseMediaType); handleWriteException(providerFactory, message, ex, firstTry); } } private MultivaluedMap<String, Object> prepareResponseHeaders( Message message, ResponseImpl response, Object entity, boolean firstTry) { MultivaluedMap<String, Object> responseHeaders = response.getMetadata(); @SuppressWarnings("unchecked") Map<String, List<Object>> userHeaders = (Map<String, List<Object>>) message.get(Message.PROTOCOL_HEADERS); if (firstTry && userHeaders != null) { responseHeaders.putAll(userHeaders); } if (entity != null) { Object customContentType = responseHeaders.getFirst(HttpHeaders.CONTENT_TYPE); if (customContentType == null) { String initialResponseContentType = (String) message.get(Message.CONTENT_TYPE); if (initialResponseContentType != null) { responseHeaders.putSingle(HttpHeaders.CONTENT_TYPE, initialResponseContentType); } } else { message.put(Message.CONTENT_TYPE, customContentType.toString()); } } message.put(Message.PROTOCOL_HEADERS, responseHeaders); setResponseDate(responseHeaders, firstTry); return responseHeaders; } private MediaType getResponseMediaType(Object mediaTypeHeader) { MediaType responseMediaType; if (mediaTypeHeader instanceof MediaType) { responseMediaType = (MediaType) mediaTypeHeader; } else { responseMediaType = mediaTypeHeader == null ? MediaType.WILDCARD_TYPE : JAXRSUtils.toMediaType(mediaTypeHeader.toString()); } return responseMediaType; } private int getActualStatus(int status, Object responseObj) { if (status == -1) { return responseObj == null ? 204 : 200; } else { return status; } } private boolean checkBufferingMode(Message m, List<WriterInterceptor> writers, boolean firstTry) { if (!firstTry) { return false; } WriterInterceptor last = writers.get(writers.size() - 1); MessageBodyWriter<Object> w = ((WriterInterceptorMBW) last).getMBW(); Object outBuf = m.getContextualProperty(OUT_BUFFERING); boolean enabled = MessageUtils.isTrue(outBuf); boolean configurableProvider = w instanceof AbstractConfigurableProvider; if (!enabled && outBuf == null && configurableProvider) { enabled = ((AbstractConfigurableProvider) w).getEnableBuffering(); } if (enabled) { boolean streamingOn = configurableProvider ? ((AbstractConfigurableProvider) w).getEnableStreaming() : false; if (streamingOn) { m.setContent(XMLStreamWriter.class, new CachingXmlEventWriter()); } else { m.setContent(OutputStream.class, new CachedOutputStream()); } } return enabled; } private void checkCachedStream(Message m, OutputStream osOriginal, boolean enabled) throws Exception { XMLStreamWriter writer = null; if (enabled) { writer = m.getContent(XMLStreamWriter.class); } else { writer = (XMLStreamWriter) m.get(XMLStreamWriter.class.getName()); } if (writer instanceof CachingXmlEventWriter) { CachingXmlEventWriter cache = (CachingXmlEventWriter) writer; if (cache.getEvents().size() != 0) { XMLStreamWriter origWriter = null; try { origWriter = StaxUtils.createXMLStreamWriter(osOriginal); for (XMLEvent event : cache.getEvents()) { StaxUtils.writeEvent(event, origWriter); } } finally { StaxUtils.close(origWriter); } } m.setContent(XMLStreamWriter.class, null); return; } if (enabled) { OutputStream os = m.getContent(OutputStream.class); if (os != osOriginal && os instanceof CachedOutputStream) { CachedOutputStream cos = (CachedOutputStream) os; if (cos.size() != 0) { cos.writeCacheTo(osOriginal); } } } } private void logWriteError(boolean firstTry, Class<?> cls, MediaType ct) { if (firstTry) { JAXRSUtils.logMessageHandlerProblem("MSG_WRITER_PROBLEM", cls, ct); } } private void handleWriteException( ServerProviderFactory pf, Message message, Throwable ex, boolean firstTry) { Response excResponse = null; if (firstTry) { excResponse = JAXRSUtils.convertFaultToResponse(ex, message); } else { message.getExchange().put(JAXRSUtils.SECOND_JAXRS_EXCEPTION, Boolean.TRUE); } if (excResponse == null) { setResponseStatus(message, 500); throw new Fault(ex); } else { serializeMessage(pf, message, excResponse, null, false); } } private void writeResponseErrorMessage( Message message, OutputStream out, String name, Class<?> cls, MediaType ct) { message.put(Message.CONTENT_TYPE, "text/plain"); message.put(Message.RESPONSE_CODE, 500); try { String errorMessage = JAXRSUtils.logMessageHandlerProblem(name, cls, ct); if (out != null) { out.write(errorMessage.getBytes(StandardCharsets.UTF_8)); } } catch (IOException another) { // ignore } } private MediaType checkFinalContentType( MediaType mt, List<WriterInterceptor> writers, boolean checkWriters) { if (checkWriters) { int mbwIndex = writers.size() == 1 ? 0 : writers.size() - 1; MessageBodyWriter<Object> writer = ((WriterInterceptorMBW) writers.get(mbwIndex)).getMBW(); Produces pm = writer.getClass().getAnnotation(Produces.class); if (pm != null) { List<MediaType> sorted = JAXRSUtils.sortMediaTypes( JAXRSUtils.getMediaTypes(pm.value()), JAXRSUtils.MEDIA_TYPE_QS_PARAM); mt = JAXRSUtils.intersectMimeTypes(sorted, mt).get(0); } } if (mt.isWildcardType() || mt.isWildcardSubtype()) { if ("application".equals(mt.getType()) || mt.isWildcardType()) { mt = MediaType.APPLICATION_OCTET_STREAM_TYPE; } else { throw ExceptionUtils.toNotAcceptableException(null, null); } } return mt; } private void setResponseDate(MultivaluedMap<String, Object> headers, boolean firstTry) { if (!firstTry || headers.containsKey(HttpHeaders.DATE)) { return; } SimpleDateFormat format = HttpUtils.getHttpDateFormat(); headers.putSingle(HttpHeaders.DATE, format.format(new Date())); } private boolean isResponseAlreadyHandled(Message m) { return isResponseAlreadyCommited(m) || isResponseRedirected(m); } private boolean isResponseAlreadyCommited(Message m) { return Boolean.TRUE.equals(m.getExchange().get(AbstractHTTPDestination.RESPONSE_COMMITED)); } private boolean isResponseRedirected(Message m) { return Boolean.TRUE.equals(m.getExchange().get(AbstractHTTPDestination.REQUEST_REDIRECTED)); } private void writeResponseToStream(OutputStream os, Object responseObj) { try { byte[] bytes = responseObj.toString().getBytes(StandardCharsets.UTF_8); os.write(bytes, 0, bytes.length); } catch (Exception ex) { LOG.severe("Problem with writing the data to the output stream"); ex.printStackTrace(); throw new RuntimeException(ex); } } private void setResponseStatus(Message message, int status) { message.put(Message.RESPONSE_CODE, status); boolean responseHeadersCopied = isResponseHeadersCopied(message); if (responseHeadersCopied) { HttpServletResponse response = (HttpServletResponse) message.get(AbstractHTTPDestination.HTTP_RESPONSE); response.setStatus(status); } } // Some CXF interceptors such as FIStaxOutInterceptor will indirectly initiate // an early copying of response code and headers into the HttpServletResponse // TODO : Pushing the filter processing and copying response headers into say // PRE-LOGICAl and PREPARE_SEND interceptors will most likely be a good thing // however JAX-RS MessageBodyWriters are also allowed to add response headers // which is reason why a MultipartMap parameter in MessageBodyWriter.writeTo // method is modifiable. Thus we do need to know if the initial copy has already // occurred: for now we will just use to ensure the correct status is set private boolean isResponseHeadersCopied(Message message) { return MessageUtils.isTrue(message.get(AbstractHTTPDestination.RESPONSE_HEADERS_COPIED)); } public void handleFault(Message message) { // complete } }
public abstract class AbstractConfigurableProvider { protected static final ResourceBundle BUNDLE = BundleUtils.getBundle(AbstractJAXBProvider.class); protected static final Logger LOG = LogUtils.getL7dLogger(AbstractJAXBProvider.class); private List<String> consumeMediaTypes; private List<String> produceMediaTypes; private boolean enableBuffering; private boolean enableStreaming; private Bus bus; /** * Sets the Bus * * @param b */ public void setBus(Bus b) { if (bus != null) { bus = b; } } /** * Gets the Bus. Providers may use the bus to resolve resource references. Example: * ResourceUtils.getResourceStream(reference, this.getBus()) * * @return */ public Bus getBus() { return bus != null ? bus : BusFactory.getThreadDefaultBus(); } /** * Sets custom Consumes media types; can be used to override static {@link Consumes} annotation * value set on the provider. * * @param types the media types */ public void setConsumeMediaTypes(List<String> types) { consumeMediaTypes = types; } /** * Gets the custom Consumes media types * * @return media types */ public List<String> getConsumeMediaTypes() { return consumeMediaTypes; } /** * Sets custom Produces media types; can be used to override static {@link Produces} annotation * value set on the provider. * * @param types the media types */ public void setProduceMediaTypes(List<String> types) { produceMediaTypes = types; } /** * Gets the custom Produces media types * * @return media types */ public List<String> getProduceMediaTypes() { return produceMediaTypes; } /** * Enables the buffering mode. If set to true then the runtime will ensure that the provider * writes to a cached stream. * * <p>For example, the JAXB marshalling process may fail after the initial XML tags have already * been written out to the HTTP output stream. Enabling the buffering ensures no incomplete * payloads are sent back to clients in case of marshalling errors at the cost of the initial * buffering - which might be negligible for small payloads. * * @param enableBuf the value of the buffering mode, false is default. */ public void setEnableBuffering(boolean enableBuf) { enableBuffering = enableBuf; } /** * Gets the value of the buffering mode * * @return true if the buffering is enabled */ public boolean getEnableBuffering() { return enableBuffering; } /** * Enables the support for streaming. XML-aware providers which prefer writing to Stax * XMLStreamWriter can set this value to true. Additionally, if the streaming and the buffering * modes are enabled, the runtime will ensure the XMLStreamWriter events are cached properly. * * @param enableStream the value of the streaming mode, false is default. */ public void setEnableStreaming(boolean enableStream) { enableStreaming = enableStream; } /** * Gets the value of the streaming mode * * @return true if the streaming is enabled */ public boolean getEnableStreaming() { return enableStreaming; } /** * Gives providers a chance to introspect the JAX-RS model classes. For example, the JAXB provider * may use the model classes to create a single composite JAXBContext supporting all the * JAXB-annotated root resource classes/types. * * @param resources */ public void init(List<ClassResourceInfo> resources) { // complete } protected boolean isPayloadEmpty(HttpHeaders headers) { if (headers != null) { return isPayloadEmpty(headers.getRequestHeaders()); } else { return false; } } protected boolean isPayloadEmpty(MultivaluedMap<String, String> headers) { return HttpUtils.isPayloadEmpty(headers); } protected void reportEmptyContentLength() throws NoContentException { String message = new org.apache.cxf.common.i18n.Message("EMPTY_BODY", BUNDLE).toString(); LOG.warning(message); throw new NoContentException(message); } }
@NoJSR250Annotations(unlessNull = "bus") public final class ConduitInitiatorManagerImpl implements ConduitInitiatorManager { private static final ResourceBundle BUNDLE = BundleUtils.getBundle(ConduitInitiatorManagerImpl.class); Map<String, ConduitInitiator> conduitInitiators; Set<String> failed = new CopyOnWriteArraySet<String>(); Set<String> loaded = new CopyOnWriteArraySet<String>(); private Bus bus; public ConduitInitiatorManagerImpl() { conduitInitiators = new ConcurrentHashMap<String, ConduitInitiator>(8, 0.75f, 4); } public ConduitInitiatorManagerImpl(Bus b) { conduitInitiators = new ConcurrentHashMap<String, ConduitInitiator>(8, 0.75f, 4); setBus(b); } @Resource public void setBus(Bus b) { bus = b; if (null != bus) { bus.setExtension(this, ConduitInitiatorManager.class); } } /* * (non-Javadoc) * * @see org.apache.cxf.bus.ConduitInitiatorManager#registerConduitInitiator(java.lang.String, * org.apache.cxf.transports.ConduitInitiator) */ public void registerConduitInitiator(String namespace, ConduitInitiator factory) { conduitInitiators.put(namespace, factory); } /* * (non-Javadoc) * * @see org.apache.cxf.bus.ConduitInitiatorManager#deregisterConduitInitiator(java.lang.String) */ public void deregisterConduitInitiator(String namespace) { conduitInitiators.remove(namespace); } /* * (non-Javadoc) * * @see org.apache.cxf.bus.ConduitInitiatorManager#ConduitInitiator(java.lang.String) */ /** * Returns the conduit initiator for the given namespace, constructing it (and storing in the * cache for future reference) if necessary, using its list of factory classname to namespace * mappings. * * @param namespace the namespace. */ public ConduitInitiator getConduitInitiator(String namespace) throws BusException { ConduitInitiator factory = conduitInitiators.get(namespace); if (factory == null && !failed.contains(namespace)) { factory = new TransportFinder<ConduitInitiator>( bus, conduitInitiators, loaded, ConduitInitiator.class) .findTransportForNamespace(namespace); } if (factory == null) { failed.add(namespace); throw new BusException(new Message("NO_CONDUIT_INITIATOR", BUNDLE, namespace)); } return factory; } @PreDestroy public void shutdown() { // nothing to do } public ConduitInitiator getConduitInitiatorForUri(String uri) { ConduitInitiator factory = new TransportFinder<ConduitInitiator>( bus, conduitInitiators, loaded, ConduitInitiator.class) .findTransportForURI(uri); return factory; } }
public class ColocOutInterceptor extends AbstractPhaseInterceptor<Message> { private static final ResourceBundle BUNDLE = BundleUtils.getBundle(ColocOutInterceptor.class); private static final Logger LOG = LogUtils.getL7dLogger(ClientImpl.class); private static final String COLOCATED = Message.class.getName() + ".COLOCATED"; private MessageObserver colocObserver; private Bus bus; public ColocOutInterceptor() { super(Phase.POST_LOGICAL); } public ColocOutInterceptor(Bus b) { super(Phase.POST_LOGICAL); bus = b; } public void setBus(Bus bus) { this.bus = bus; } public void handleMessage(Message message) throws Fault { if (bus == null) { bus = message.getExchange().getBus(); if (bus == null) { bus = BusFactory.getDefaultBus(false); } if (bus == null) { throw new Fault(new org.apache.cxf.common.i18n.Message("BUS_NOT_FOUND", BUNDLE)); } } ServerRegistry registry = bus.getExtension(ServerRegistry.class); if (registry == null) { throw new Fault(new org.apache.cxf.common.i18n.Message("SERVER_REGISTRY_NOT_FOUND", BUNDLE)); } Exchange exchange = message.getExchange(); Endpoint senderEndpoint = exchange.getEndpoint(); if (senderEndpoint == null) { throw new Fault(new org.apache.cxf.common.i18n.Message("ENDPOINT_NOT_FOUND", BUNDLE)); } BindingOperationInfo boi = exchange.getBindingOperationInfo(); if (boi == null) { throw new Fault(new org.apache.cxf.common.i18n.Message("OPERATIONINFO_NOT_FOUND", BUNDLE)); } Server srv = isColocated(registry.getServers(), senderEndpoint, boi); if (srv != null) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Operation:" + boi.getName() + " dispatched as colocated call."); } InterceptorChain outChain = message.getInterceptorChain(); outChain.abort(); exchange.put(Bus.class, bus); message.put(COLOCATED, Boolean.TRUE); message.put(Message.WSDL_OPERATION, boi.getName()); message.put(Message.WSDL_INTERFACE, boi.getBinding().getInterface().getName()); invokeColocObserver(message, srv.getEndpoint()); if (!exchange.isOneWay()) { invokeInboundChain(exchange, senderEndpoint); } } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Operation:" + boi.getName() + " dispatched as remote call."); } message.put(COLOCATED, Boolean.FALSE); } } protected void invokeColocObserver(Message outMsg, Endpoint inboundEndpoint) { if (colocObserver == null) { colocObserver = new ColocMessageObserver(inboundEndpoint, bus); } if (LOG.isLoggable(Level.FINE)) { LOG.fine("Invoke on Coloc Observer."); } colocObserver.onMessage(outMsg); } protected void invokeInboundChain(Exchange ex, Endpoint ep) { Message m = getInBoundMessage(ex); Message inMsg = ep.getBinding().createMessage(); MessageImpl.copyContent(m, inMsg); // Copy Response Context to Client inBound Message // TODO a Context Filter Strategy required. inMsg.putAll(m); inMsg.put(Message.REQUESTOR_ROLE, Boolean.TRUE); inMsg.put(Message.INBOUND_MESSAGE, Boolean.TRUE); inMsg.setExchange(ex); Exception exc = inMsg.getContent(Exception.class); if (exc != null) { ex.setInFaultMessage(inMsg); ColocInFaultObserver observer = new ColocInFaultObserver(bus); observer.onMessage(inMsg); } else { // Handle Response ex.setInMessage(inMsg); PhaseManager pm = bus.getExtension(PhaseManager.class); SortedSet<Phase> phases = new TreeSet<Phase>(pm.getInPhases()); ColocUtil.setPhases(phases, Phase.USER_LOGICAL, Phase.PRE_INVOKE); InterceptorChain chain = ColocUtil.getInInterceptorChain(ex, phases); inMsg.setInterceptorChain(chain); chain.doIntercept(inMsg); } ex.put(ClientImpl.FINISHED, Boolean.TRUE); } protected Message getInBoundMessage(Exchange ex) { return (ex.getInFaultMessage() != null) ? ex.getInFaultMessage() : ex.getInMessage(); } protected void setMessageObserver(MessageObserver observer) { colocObserver = observer; } protected Server isColocated(List<Server> servers, Endpoint endpoint, BindingOperationInfo boi) { if (servers != null) { Service senderService = endpoint.getService(); EndpointInfo senderEI = endpoint.getEndpointInfo(); for (Server s : servers) { Endpoint receiverEndpoint = s.getEndpoint(); Service receiverService = receiverEndpoint.getService(); EndpointInfo receiverEI = receiverEndpoint.getEndpointInfo(); if (receiverService.getName().equals(senderService.getName()) && receiverEI.getName().equals(senderEI.getName())) { // Check For Operation Match. BindingOperationInfo receiverOI = receiverEI.getBinding().getOperation(boi.getName()); if (receiverOI != null && isCompatibleOperationInfo(boi, receiverOI)) { return s; } } } } return null; } protected boolean isSameOperationInfo( BindingOperationInfo sender, BindingOperationInfo receiver) { return ColocUtil.isSameOperationInfo(sender.getOperationInfo(), receiver.getOperationInfo()); } protected boolean isCompatibleOperationInfo( BindingOperationInfo sender, BindingOperationInfo receiver) { return ColocUtil.isCompatibleOperationInfo( sender.getOperationInfo(), receiver.getOperationInfo()); } public void setExchangeProperties(Exchange exchange, Endpoint ep) { exchange.put(Endpoint.class, ep); exchange.put(Service.class, ep.getService()); exchange.put(Binding.class, ep.getBinding()); exchange.put(Bus.class, bus == null ? BusFactory.getDefaultBus(false) : bus); } }
/** Proxy-based client implementation */ public class ClientProxyImpl extends AbstractClient implements InvocationHandlerAware, InvocationHandler { private static final Logger LOG = LogUtils.getL7dLogger(ClientProxyImpl.class); private static final ResourceBundle BUNDLE = BundleUtils.getBundle(ClientProxyImpl.class); private static final String SLASH = "/"; private static final String BUFFER_PROXY_RESPONSE = "buffer.proxy.response"; private ClassResourceInfo cri; private ClassLoader proxyLoader; private boolean inheritHeaders; private boolean isRoot; private Map<String, Object> valuesMap = Collections.emptyMap(); private BodyWriter bodyWriter = new BodyWriter(); public ClientProxyImpl( URI baseURI, ClassLoader loader, ClassResourceInfo cri, boolean isRoot, boolean inheritHeaders, Object... varValues) { this(new LocalClientState(baseURI), loader, cri, isRoot, inheritHeaders, varValues); } public ClientProxyImpl( ClientState initialState, ClassLoader loader, ClassResourceInfo cri, boolean isRoot, boolean inheritHeaders, Object... varValues) { super(initialState); this.proxyLoader = loader; this.cri = cri; this.isRoot = isRoot; this.inheritHeaders = inheritHeaders; initValuesMap(varValues); } private void initValuesMap(Object... varValues) { if (isRoot) { List<String> vars = cri.getURITemplate().getVariables(); valuesMap = new LinkedHashMap<String, Object>(); for (int i = 0; i < vars.size(); i++) { if (varValues.length > 0) { if (i < varValues.length) { valuesMap.put(vars.get(i), varValues[i]); } else { org.apache.cxf.common.i18n.Message msg = new org.apache.cxf.common.i18n.Message( "ROOT_VARS_MISMATCH", BUNDLE, vars.size(), varValues.length); LOG.info(msg.toString()); break; } } else { valuesMap.put(vars.get(i), ""); } } } } /** * Updates the current state if Client method is invoked, otherwise does the remote invocation or * returns a new proxy if subresource method is invoked. Can throw an expected exception if * ResponseExceptionMapper is registered */ public Object invoke(Object o, Method m, Object[] params) throws Throwable { Class<?> declaringClass = m.getDeclaringClass(); if (Client.class == declaringClass || InvocationHandlerAware.class == declaringClass || Object.class == declaringClass) { return m.invoke(this, params); } resetResponse(); OperationResourceInfo ori = cri.getMethodDispatcher().getOperationResourceInfo(m); if (ori == null) { reportInvalidResourceMethod(m, "INVALID_RESOURCE_METHOD"); } MultivaluedMap<ParameterType, Parameter> types = getParametersInfo(m, params, ori); List<Parameter> beanParamsList = getParameters(types, ParameterType.BEAN); int bodyIndex = getBodyIndex(types, ori); List<Object> pathParams = getPathParamValues(m, params, types, beanParamsList, ori, bodyIndex); UriBuilder builder = getCurrentBuilder().clone(); if (isRoot) { addNonEmptyPath(builder, ori.getClassResourceInfo().getURITemplate().getValue()); } addNonEmptyPath(builder, ori.getURITemplate().getValue()); handleMatrixes(m, params, types, beanParamsList, builder); handleQueries(m, params, types, beanParamsList, builder); URI uri = builder.buildFromEncoded(pathParams.toArray()).normalize(); MultivaluedMap<String, String> headers = getHeaders(); MultivaluedMap<String, String> paramHeaders = new MetadataMap<String, String>(); handleHeaders(m, params, paramHeaders, beanParamsList, types); handleCookies(m, params, paramHeaders, beanParamsList, types); if (ori.isSubResourceLocator()) { ClassResourceInfo subCri = cri.getSubResource(m.getReturnType(), m.getReturnType()); if (subCri == null) { reportInvalidResourceMethod(m, "INVALID_SUBRESOURCE"); } MultivaluedMap<String, String> subHeaders = paramHeaders; if (inheritHeaders) { subHeaders.putAll(headers); } ClientState newState = getState() .newState( uri, subHeaders, getTemplateParametersMap(ori.getURITemplate(), pathParams)); ClientProxyImpl proxyImpl = new ClientProxyImpl(newState, proxyLoader, subCri, false, inheritHeaders); proxyImpl.setConfiguration(getConfiguration()); return JAXRSClientFactory.createProxy(m.getReturnType(), proxyLoader, proxyImpl); } headers.putAll(paramHeaders); getState().setTemplates(getTemplateParametersMap(ori.getURITemplate(), pathParams)); Object body = null; if (bodyIndex != -1) { body = params[bodyIndex]; if (body == null) { bodyIndex = -1; } } else if (types.containsKey(ParameterType.FORM)) { body = handleForm(m, params, types, beanParamsList); } else if (types.containsKey(ParameterType.REQUEST_BODY)) { body = handleMultipart(types, ori, params); } setRequestHeaders( headers, ori, types.containsKey(ParameterType.FORM), body == null ? null : body.getClass(), m.getReturnType()); return doChainedInvocation(uri, headers, ori, body, bodyIndex, null, null); } private void addNonEmptyPath(UriBuilder builder, String pathValue) { if (!SLASH.equals(pathValue)) { builder.path(pathValue); } } private static MultivaluedMap<ParameterType, Parameter> getParametersInfo( Method m, Object[] params, OperationResourceInfo ori) { MultivaluedMap<ParameterType, Parameter> map = new MetadataMap<ParameterType, Parameter>(); List<Parameter> parameters = ori.getParameters(); if (parameters.size() == 0) { return map; } int requestBodyParam = 0; int multipartParam = 0; for (Parameter p : parameters) { if (isIgnorableParameter(m, p)) { continue; } if (p.getType() == ParameterType.REQUEST_BODY) { requestBodyParam++; if (getMultipart(ori, p.getIndex()) != null) { multipartParam++; } } map.add(p.getType(), p); } if (map.containsKey(ParameterType.REQUEST_BODY)) { if (requestBodyParam > 1 && requestBodyParam != multipartParam) { reportInvalidResourceMethod(ori.getMethodToInvoke(), "SINGLE_BODY_ONLY"); } if (map.containsKey(ParameterType.FORM)) { reportInvalidResourceMethod(ori.getMethodToInvoke(), "ONLY_FORM_ALLOWED"); } } return map; } private static boolean isIgnorableParameter(Method m, Parameter p) { if (p.getType() == ParameterType.CONTEXT) { return true; } return p.getType() == ParameterType.REQUEST_BODY && m.getParameterTypes()[p.getIndex()] == AsyncResponse.class; } private static int getBodyIndex( MultivaluedMap<ParameterType, Parameter> map, OperationResourceInfo ori) { List<Parameter> list = map.get(ParameterType.REQUEST_BODY); int index = list == null || list.size() > 1 ? -1 : list.get(0).getIndex(); if (ori.isSubResourceLocator() && index != -1) { reportInvalidResourceMethod(ori.getMethodToInvoke(), "NO_BODY_IN_SUBRESOURCE"); } return index; } private void checkResponse(Method m, Response r, Message inMessage) throws Throwable { Throwable t = null; int status = r.getStatus(); if (status >= 300) { Class<?>[] exTypes = m.getExceptionTypes(); if (exTypes.length == 0) { exTypes = new Class[] {WebApplicationException.class}; } for (Class<?> exType : exTypes) { ResponseExceptionMapper<?> mapper = findExceptionMapper(inMessage, exType); if (mapper != null) { t = mapper.fromResponse(r); if (t != null) { throw t; } } } if ((t == null) && (m.getReturnType() == Response.class) && (m.getExceptionTypes().length == 0)) { return; } t = convertToWebApplicationException(r); if (inMessage.getExchange().get(Message.RESPONSE_CODE) == null) { throw t; } Endpoint ep = inMessage.getExchange().getEndpoint(); inMessage.getExchange().put(InterceptorProvider.class, getConfiguration()); inMessage.setContent(Exception.class, new Fault(t)); inMessage.getInterceptorChain().abort(); if (ep.getInFaultObserver() != null) { ep.getInFaultObserver().onMessage(inMessage); } throw t; } } private static ResponseExceptionMapper<?> findExceptionMapper(Message message, Class<?> exType) { ClientProviderFactory pf = ClientProviderFactory.getInstance(message); return pf.createResponseExceptionMapper(message, exType); } private MultivaluedMap<String, String> setRequestHeaders( MultivaluedMap<String, String> headers, OperationResourceInfo ori, boolean formParams, Class<?> bodyClass, Class<?> responseClass) { if (headers.getFirst(HttpHeaders.CONTENT_TYPE) == null) { if (formParams || bodyClass != null && MultivaluedMap.class.isAssignableFrom(bodyClass)) { headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); } else { String ctType = null; List<MediaType> consumeTypes = ori.getConsumeTypes(); if (!consumeTypes.isEmpty() && !consumeTypes.get(0).equals(MediaType.WILDCARD_TYPE)) { ctType = JAXRSUtils.mediaTypeToString(ori.getConsumeTypes().get(0)); } else if (bodyClass != null) { ctType = MediaType.APPLICATION_XML; } if (ctType != null) { headers.putSingle(HttpHeaders.CONTENT_TYPE, ctType); } } } List<MediaType> accepts = getAccept(headers); if (accepts == null) { boolean produceWildcard = ori.getProduceTypes().size() == 0 || ori.getProduceTypes().get(0).equals(MediaType.WILDCARD_TYPE); if (produceWildcard) { accepts = InjectionUtils.isPrimitive(responseClass) ? Collections.singletonList(MediaType.TEXT_PLAIN_TYPE) : Collections.singletonList(MediaType.APPLICATION_XML_TYPE); } else if (responseClass == Void.class || responseClass == Void.TYPE) { accepts = Collections.singletonList(MediaType.WILDCARD_TYPE); } else { accepts = ori.getProduceTypes(); } for (MediaType mt : accepts) { headers.add(HttpHeaders.ACCEPT, JAXRSUtils.mediaTypeToString(mt)); } } return headers; } private List<MediaType> getAccept(MultivaluedMap<String, String> allHeaders) { List<String> headers = allHeaders.get(HttpHeaders.ACCEPT); if (headers == null || headers.size() == 0) { return null; } List<MediaType> types = new ArrayList<MediaType>(); for (String s : headers) { types.add(JAXRSUtils.toMediaType(s)); } return types; } private List<Object> getPathParamValues( Method m, Object[] params, MultivaluedMap<ParameterType, Parameter> map, List<Parameter> beanParams, OperationResourceInfo ori, int bodyIndex) { List<Object> list = new LinkedList<Object>(); List<String> methodVars = ori.getURITemplate().getVariables(); List<Parameter> paramsList = getParameters(map, ParameterType.PATH); Map<String, BeanPair> beanParamValues = new HashMap<String, BeanPair>(beanParams.size()); for (Parameter p : beanParams) { beanParamValues.putAll(getValuesFromBeanParam(params[p.getIndex()], PathParam.class)); } if (!beanParamValues.isEmpty() && !methodVars.containsAll(beanParamValues.keySet())) { List<String> classVars = ori.getClassResourceInfo().getURITemplate().getVariables(); for (String classVar : classVars) { BeanPair pair = beanParamValues.get(classVar); if (pair != null) { Object paramValue = convertParamValue(pair.getValue(), pair.getAnns()); if (isRoot) { valuesMap.put(classVar, paramValue); } else { list.add(paramValue); } } } } if (isRoot) { list.addAll(valuesMap.values()); } Map<String, Parameter> paramsMap = new LinkedHashMap<String, Parameter>(); for (Parameter p : paramsList) { if (p.getName().length() == 0) { MultivaluedMap<String, Object> values = InjectionUtils.extractValuesFromBean(params[p.getIndex()], ""); for (String var : methodVars) { list.addAll(values.get(var)); } } else { paramsMap.put(p.getName(), p); } } Object requestBody = bodyIndex == -1 ? null : params[bodyIndex]; for (String varName : methodVars) { Parameter p = paramsMap.remove(varName); if (p != null) { list.add(convertParamValue(params[p.getIndex()], getParamAnnotations(m, p))); } else if (beanParamValues.containsKey(varName)) { BeanPair pair = beanParamValues.get(varName); list.add(convertParamValue(pair.getValue(), pair.getAnns())); } else if (requestBody != null) { try { Method getter = requestBody .getClass() .getMethod("get" + StringUtils.capitalize(varName), new Class<?>[] {}); list.add(getter.invoke(requestBody, new Object[] {})); } catch (Exception ex) { // continue } } } for (Parameter p : paramsMap.values()) { if (valuesMap.containsKey(p.getName())) { int index = 0; for (Iterator<String> it = valuesMap.keySet().iterator(); it.hasNext(); index++) { if (it.next().equals(p.getName()) && index < list.size()) { list.remove(index); list.add(index, convertParamValue(params[p.getIndex()], null)); break; } } } } return list; } private static Annotation[] getParamAnnotations(Method m, Parameter p) { return m.getParameterAnnotations()[p.getIndex()]; } @SuppressWarnings("unchecked") private static List<Parameter> getParameters( MultivaluedMap<ParameterType, Parameter> map, ParameterType key) { return map.get(key) == null ? Collections.EMPTY_LIST : map.get(key); } private void handleQueries( Method m, Object[] params, MultivaluedMap<ParameterType, Parameter> map, List<Parameter> beanParams, UriBuilder ub) { List<Parameter> qs = getParameters(map, ParameterType.QUERY); for (Parameter p : qs) { if (params[p.getIndex()] != null) { addMatrixQueryParamsToBuilder( ub, p.getName(), ParameterType.QUERY, getParamAnnotations(m, p), params[p.getIndex()]); } } for (Parameter p : beanParams) { Map<String, BeanPair> values = getValuesFromBeanParam(params[p.getIndex()], QueryParam.class); for (Map.Entry<String, BeanPair> entry : values.entrySet()) { if (entry.getValue() != null) { addMatrixQueryParamsToBuilder( ub, entry.getKey(), ParameterType.QUERY, entry.getValue().getAnns(), entry.getValue().getValue()); } } } } private Map<String, BeanPair> getValuesFromBeanParam( Object bean, Class<? extends Annotation> annClass) { Map<String, BeanPair> values = new HashMap<String, BeanPair>(); getValuesFromBeanParam(bean, annClass, values); return values; } private Map<String, BeanPair> getValuesFromBeanParam( Object bean, Class<? extends Annotation> annClass, Map<String, BeanPair> values) { for (Method m : bean.getClass().getMethods()) { if (m.getName().startsWith("set")) { try { String propertyName = m.getName().substring(3); Annotation annotation = m.getAnnotation(annClass); boolean beanParam = m.getAnnotation(BeanParam.class) != null; if (annotation != null || beanParam) { Method getter = bean.getClass().getMethod("get" + propertyName, new Class[] {}); Object value = getter.invoke(bean, new Object[] {}); if (value != null) { if (annotation != null) { String annotationValue = AnnotationUtils.getAnnotationValue(annotation); values.put(annotationValue, new BeanPair(value, m.getParameterAnnotations()[0])); } else { getValuesFromBeanParam(value, annClass, values); } } } else { String fieldName = StringUtils.uncapitalize(propertyName); Field f = InjectionUtils.getDeclaredField(bean.getClass(), fieldName); if (f == null) { continue; } annotation = f.getAnnotation(annClass); if (annotation != null) { Object value = ReflectionUtil.accessDeclaredField(f, bean, Object.class); if (value != null) { String annotationValue = AnnotationUtils.getAnnotationValue(annotation); values.put(annotationValue, new BeanPair(value, f.getAnnotations())); } } else if (f.getAnnotation(BeanParam.class) != null) { Object value = ReflectionUtil.accessDeclaredField(f, bean, Object.class); if (value != null) { getValuesFromBeanParam(value, annClass, values); } } } } catch (Throwable t) { // ignore } } } return values; } private void handleMatrixes( Method m, Object[] params, MultivaluedMap<ParameterType, Parameter> map, List<Parameter> beanParams, UriBuilder ub) { List<Parameter> mx = getParameters(map, ParameterType.MATRIX); for (Parameter p : mx) { if (params[p.getIndex()] != null) { addMatrixQueryParamsToBuilder( ub, p.getName(), ParameterType.MATRIX, getParamAnnotations(m, p), params[p.getIndex()]); } } for (Parameter p : beanParams) { Map<String, BeanPair> values = getValuesFromBeanParam(params[p.getIndex()], MatrixParam.class); for (Map.Entry<String, BeanPair> entry : values.entrySet()) { if (entry.getValue() != null) { addMatrixQueryParamsToBuilder( ub, entry.getKey(), ParameterType.MATRIX, entry.getValue().getAnns(), entry.getValue().getValue()); } } } } private MultivaluedMap<String, String> handleForm( Method m, Object[] params, MultivaluedMap<ParameterType, Parameter> map, List<Parameter> beanParams) { MultivaluedMap<String, String> form = new MetadataMap<String, String>(); List<Parameter> fm = getParameters(map, ParameterType.FORM); for (Parameter p : fm) { addFormValue(form, p.getName(), params[p.getIndex()], getParamAnnotations(m, p)); } for (Parameter p : beanParams) { Map<String, BeanPair> values = getValuesFromBeanParam(params[p.getIndex()], FormParam.class); for (Map.Entry<String, BeanPair> entry : values.entrySet()) { addFormValue(form, entry.getKey(), entry.getValue().getValue(), entry.getValue().getAnns()); } } return form; } private void addFormValue( MultivaluedMap<String, String> form, String name, Object pValue, Annotation[] anns) { if (pValue != null) { if (InjectionUtils.isSupportedCollectionOrArray(pValue.getClass())) { Collection<?> c = pValue.getClass().isArray() ? Arrays.asList((Object[]) pValue) : (Collection<?>) pValue; for (Iterator<?> it = c.iterator(); it.hasNext(); ) { FormUtils.addPropertyToForm(form, name, convertParamValue(it.next(), anns)); } } else { FormUtils.addPropertyToForm( form, name, name.isEmpty() ? pValue : convertParamValue(pValue, anns)); } } } private List<Attachment> handleMultipart( MultivaluedMap<ParameterType, Parameter> map, OperationResourceInfo ori, Object[] params) { List<Attachment> atts = new LinkedList<Attachment>(); List<Parameter> fm = getParameters(map, ParameterType.REQUEST_BODY); for (Parameter p : fm) { Multipart part = getMultipart(ori, p.getIndex()); if (part != null) { Object partObject = params[p.getIndex()]; if (partObject != null) { atts.add(new Attachment(part.value(), part.type(), partObject)); } } } return atts; } private void handleHeaders( Method m, Object[] params, MultivaluedMap<String, String> headers, List<Parameter> beanParams, MultivaluedMap<ParameterType, Parameter> map) { List<Parameter> hs = getParameters(map, ParameterType.HEADER); for (Parameter p : hs) { if (params[p.getIndex()] != null) { headers.add( p.getName(), convertParamValue(params[p.getIndex()], getParamAnnotations(m, p))); } } for (Parameter p : beanParams) { Map<String, BeanPair> values = getValuesFromBeanParam(params[p.getIndex()], HeaderParam.class); for (Map.Entry<String, BeanPair> entry : values.entrySet()) { if (entry.getValue() != null) { headers.add( entry.getKey(), convertParamValue(entry.getValue().getValue(), entry.getValue().getAnns())); } } } } private static Multipart getMultipart(OperationResourceInfo ori, int index) { Method aMethod = ori.getAnnotatedMethod(); return aMethod != null ? AnnotationUtils.getAnnotation(aMethod.getParameterAnnotations()[index], Multipart.class) : null; } private void handleCookies( Method m, Object[] params, MultivaluedMap<String, String> headers, List<Parameter> beanParams, MultivaluedMap<ParameterType, Parameter> map) { List<Parameter> cs = getParameters(map, ParameterType.COOKIE); for (Parameter p : cs) { if (params[p.getIndex()] != null) { headers.add( HttpHeaders.COOKIE, p.getName() + '=' + convertParamValue(params[p.getIndex()].toString(), getParamAnnotations(m, p))); } } for (Parameter p : beanParams) { Map<String, BeanPair> values = getValuesFromBeanParam(params[p.getIndex()], CookieParam.class); for (Map.Entry<String, BeanPair> entry : values.entrySet()) { if (entry.getValue() != null) { headers.add( HttpHeaders.COOKIE, entry.getKey() + "=" + convertParamValue(entry.getValue().getValue(), entry.getValue().getAnns())); } } } } private Object doChainedInvocation( URI uri, MultivaluedMap<String, String> headers, OperationResourceInfo ori, Object body, int bodyIndex, Exchange exchange, Map<String, Object> invocationContext) throws Throwable { Bus configuredBus = getConfiguration().getBus(); Bus origBus = BusFactory.getAndSetThreadDefaultBus(configuredBus); ClassLoaderHolder origLoader = null; try { ClassLoader loader = configuredBus.getExtension(ClassLoader.class); if (loader != null) { origLoader = ClassLoaderUtils.setThreadContextClassloader(loader); } Message outMessage = createMessage(body, ori.getHttpMethod(), headers, uri, exchange, invocationContext, true); if (bodyIndex != -1) { outMessage.put(Type.class, ori.getMethodToInvoke().getGenericParameterTypes()[bodyIndex]); } outMessage.getExchange().setOneWay(ori.isOneway()); setSupportOnewayResponseProperty(outMessage); outMessage.setContent(OperationResourceInfo.class, ori); setPlainOperationNameProperty(outMessage, ori.getMethodToInvoke().getName()); outMessage.getExchange().put(Method.class, ori.getMethodToInvoke()); outMessage.put( Annotation.class.getName(), getMethodAnnotations(ori.getAnnotatedMethod(), bodyIndex)); if (body != null) { outMessage.put("BODY_INDEX", bodyIndex); } outMessage.getInterceptorChain().add(bodyWriter); Map<String, Object> reqContext = getRequestContext(outMessage); reqContext.put(OperationResourceInfo.class.getName(), ori); reqContext.put("BODY_INDEX", bodyIndex); // execute chain doRunInterceptorChain(outMessage); Object[] results = preProcessResult(outMessage); if (results != null && results.length == 1) { return results[0]; } try { return handleResponse(outMessage, ori.getClassResourceInfo().getServiceClass()); } finally { completeExchange(outMessage.getExchange(), true); } } finally { if (origLoader != null) { origLoader.reset(); } if (origBus != configuredBus) { BusFactory.setThreadDefaultBus(origBus); } } } @Override protected Object retryInvoke( URI newRequestURI, MultivaluedMap<String, String> headers, Object body, Exchange exchange, Map<String, Object> invContext) throws Throwable { Map<String, Object> reqContext = CastUtils.cast((Map<?, ?>) invContext.get(REQUEST_CONTEXT)); int bodyIndex = body != null ? (Integer) reqContext.get("BODY_INDEX") : -1; OperationResourceInfo ori = (OperationResourceInfo) reqContext.get(OperationResourceInfo.class.getName()); return doChainedInvocation(newRequestURI, headers, ori, body, bodyIndex, exchange, invContext); } protected Object handleResponse(Message outMessage, Class<?> serviceCls) throws Throwable { try { Response r = setResponseBuilder(outMessage, outMessage.getExchange()).build(); ((ResponseImpl) r).setOutMessage(outMessage); getState().setResponse(r); Method method = outMessage.getExchange().get(Method.class); checkResponse(method, r, outMessage); if (method.getReturnType() == Void.class || method.getReturnType() == Void.TYPE) { return null; } if (method.getReturnType() == Response.class && (r.getEntity() == null || InputStream.class.isAssignableFrom(r.getEntity().getClass()) && ((InputStream) r.getEntity()).available() == 0)) { return r; } if (PropertyUtils.isTrue( super.getConfiguration().getResponseContext().get(BUFFER_PROXY_RESPONSE))) { r.bufferEntity(); } Class<?> returnType = method.getReturnType(); Type genericType = InjectionUtils.processGenericTypeIfNeeded( serviceCls, returnType, method.getGenericReturnType()); returnType = InjectionUtils.updateParamClassToTypeIfNeeded(returnType, genericType); return readBody(r, outMessage, returnType, genericType, method.getDeclaredAnnotations()); } finally { ClientProviderFactory.getInstance(outMessage).clearThreadLocalProxies(); } } public Object getInvocationHandler() { return this; } protected static void reportInvalidResourceMethod(Method m, String name) { org.apache.cxf.common.i18n.Message errorMsg = new org.apache.cxf.common.i18n.Message( name, BUNDLE, m.getDeclaringClass().getName(), m.getName()); LOG.severe(errorMsg.toString()); throw new ProcessingException(errorMsg.toString()); } protected static Annotation[] getMethodAnnotations(Method aMethod, int bodyIndex) { return aMethod == null || bodyIndex == -1 ? new Annotation[0] : aMethod.getParameterAnnotations()[bodyIndex]; } private class BodyWriter extends AbstractBodyWriter { protected void doWriteBody( Message outMessage, Object body, Type bodyType, Annotation[] customAnns, OutputStream os) throws Fault { OperationResourceInfo ori = outMessage.getContent(OperationResourceInfo.class); if (ori == null) { return; } Method method = ori.getMethodToInvoke(); int bodyIndex = (Integer) outMessage.get("BODY_INDEX"); Annotation[] anns = customAnns != null ? customAnns : getMethodAnnotations(ori.getAnnotatedMethod(), bodyIndex); try { if (bodyIndex != -1) { Class<?> paramClass = method.getParameterTypes()[bodyIndex]; Class<?> bodyClass = paramClass.isAssignableFrom(body.getClass()) ? paramClass : body.getClass(); Type genericType = method.getGenericParameterTypes()[bodyIndex]; if (bodyType != null) { genericType = bodyType; } genericType = InjectionUtils.processGenericTypeIfNeeded( ori.getClassResourceInfo().getServiceClass(), bodyClass, genericType); bodyClass = InjectionUtils.updateParamClassToTypeIfNeeded(bodyClass, genericType); writeBody(body, outMessage, bodyClass, genericType, anns, os); } else { Type paramType = body.getClass(); if (bodyType != null) { paramType = bodyType; } writeBody(body, outMessage, body.getClass(), paramType, anns, os); } } catch (Exception ex) { throw new Fault(ex); } } } private static class BeanPair { private Object value; private Annotation[] anns; BeanPair(Object value, Annotation[] anns) { this.value = value; this.anns = anns; } public Object getValue() { return value; } public Annotation[] getAnns() { return anns; } } }