private Object invokeFunction( Method method, Object customObj, Object source, String[][] parameters) throws Exception { Class<?>[] prmTypes = method.getParameterTypes(); Object[] methodPrms = new Object[prmTypes.length]; methodPrms[0] = source; for (int parameterNdx = 0, methodPrmNdx = 1; parameterNdx < parameters.length; parameterNdx++, methodPrmNdx++) { if (method.isVarArgs() && methodPrmNdx == prmTypes.length - 1) { Object array = Array.newInstance( prmTypes[methodPrmNdx].getComponentType(), parameters.length - parameterNdx); for (int arrayNdx = 0; parameterNdx < parameters.length; parameterNdx++, arrayNdx++) { String[] parts = parameters[parameterNdx]; Array.set( array, arrayNdx, resolver.resolveClass(parts[0]).getConstructor(String.class).newInstance(parts[1])); } methodPrms[methodPrmNdx] = array; } else { String[] parts = parameters[parameterNdx]; methodPrms[methodPrmNdx] = resolver.resolveClass(parts[0]).getConstructor(String.class).newInstance(parts[1]); } } return method.invoke(customObj, methodPrms); }
private boolean parametersMatchParameterList(Class<?>[] prmTypes, String[][] parameters) { int ndx = 0; while (ndx < prmTypes.length) { Class<?> prmType = prmTypes[ndx]; if (ndx >= parameters.length) { return ndx == prmTypes.length - 1 && prmType.isArray(); } if (ndx == prmTypes.length - 1 && prmType.isArray()) { // Assume this only occurs for functions with var args Class<?> varArgClass = prmType.getComponentType(); while (ndx < parameters.length) { Class<?> prmClass = resolver.resolveClass(parameters[ndx][0]); if (!varArgClass.isAssignableFrom(prmClass)) { return false; } ndx++; } } else { Class<?> prmClass = resolver.resolveClass(parameters[ndx][0]); if (!prmTypes[ndx].isAssignableFrom(prmClass)) { return false; } } ndx++; } return true; }
Object mapCustom(Object source, Class<?> sourceClass) { // The converter parameter is stored in a thread local variable, so // we need to parse the parameter on each invocation // ex: custom-converter-param="org.example.MyMapping,map" // className = org.example.MyMapping // operation = map String[] prms = getParameter().split(","); String className = prms[0]; String operation = prms.length > 1 ? prms[1] : null; // now attempt to process any additional parameters passed along // ex: // custom-converter-param="org.example.MyMapping,substring,java.lang.Integer=3,java.lang.Integer=10" // className = org.example.MyMapping // operation = substring // parameters = ["java.lang.Integer=3","java.lang.Integer=10"] String[][] prmTypesAndValues; if (prms.length > 2) { // Break parameters down into types and values prmTypesAndValues = new String[prms.length - 2][2]; for (int ndx = 0; ndx < prmTypesAndValues.length; ndx++) { String prm = prms[ndx + 2]; String[] parts = prm.split("="); if (parts.length != 2) { throw new RuntimeException("Value missing for parameter " + prm); } prmTypesAndValues[ndx][0] = parts[0]; prmTypesAndValues[ndx][1] = parts[1]; } } else { prmTypesAndValues = null; } Object customObj; Method method; try { Class<?> customClass = resolver.resolveMandatoryClass(className); customObj = customClass.newInstance(); // If a specific mapping operation has been supplied use that if (operation != null && prmTypesAndValues != null) { method = selectMethod(customClass, operation, sourceClass, prmTypesAndValues); } else if (operation != null) { method = customClass.getMethod(operation, sourceClass); } else { method = selectMethod(customClass, sourceClass); } } catch (Exception e) { throw new RuntimeException("Failed to load custom function", e); } // Verify that we found a matching method if (method == null) { throw new RuntimeException("No eligible custom function methods in " + className); } // Invoke the custom mapping method try { if (prmTypesAndValues != null) { return invokeFunction(method, customObj, source, prmTypesAndValues); } else { return method.invoke(customObj, source); } } catch (Exception e) { throw new RuntimeException("Error while invoking custom function", e); } }
protected XStream createXStream(ClassResolver resolver, ClassLoader classLoader) { if (xstreamDriver != null) { xstream = new XStream(xstreamDriver); } else { xstream = new XStream(); } if (mode != null) { xstream.setMode(getModeFromString(mode)); } ClassLoader xstreamLoader = xstream.getClassLoader(); if (classLoader != null && xstreamLoader instanceof CompositeClassLoader) { ((CompositeClassLoader) xstreamLoader).add(classLoader); } try { if (this.implicitCollections != null) { for (Entry<String, String[]> entry : this.implicitCollections.entrySet()) { for (String name : entry.getValue()) { xstream.addImplicitCollection(resolver.resolveMandatoryClass(entry.getKey()), name); } } } if (this.aliases != null) { for (Entry<String, String> entry : this.aliases.entrySet()) { xstream.alias(entry.getKey(), resolver.resolveMandatoryClass(entry.getValue())); // It can turn the auto-detection mode off xstream.processAnnotations(resolver.resolveMandatoryClass(entry.getValue())); } } if (this.omitFields != null) { for (Entry<String, String[]> entry : this.omitFields.entrySet()) { for (String name : entry.getValue()) { xstream.omitField(resolver.resolveMandatoryClass(entry.getKey()), name); } } } if (this.converters != null) { for (String name : this.converters) { Class<Converter> converterClass = resolver.resolveMandatoryClass(name, Converter.class); Converter converter; Constructor<Converter> con = null; try { con = converterClass.getDeclaredConstructor(new Class[] {XStream.class}); } catch (Exception e) { // swallow as we null check in a moment. } if (con != null) { converter = con.newInstance(xstream); } else { converter = converterClass.newInstance(); try { Method method = converterClass.getMethod("setXStream", new Class[] {XStream.class}); if (method != null) { ObjectHelper.invokeMethod(method, converter, xstream); } } catch (Throwable e) { // swallow, as it just means the user never add an XStream setter, which is optional } } xstream.registerConverter(converter); } } addDefaultPermissions(xstream); if (this.permissions != null) { // permissions ::= pterm (',' pterm)* # consits of one or more terms // pterm ::= aod? wterm # each term preceded by an optional sign // aod ::= '+' | '-' # indicates allow or deny where allow if omitted // wterm ::= a class name with optional wildcard characters addPermissions(xstream, permissions); } } catch (Exception e) { throw new RuntimeException("Unable to build XStream instance", e); } return xstream; }
private void parse( Swagger swagger, RestDefinition rest, String camelContextId, ClassResolver classResolver) { List<VerbDefinition> verbs = new ArrayList<>(rest.getVerbs()); // must sort the verbs by uri so we group them together when an uri has multiple operations Collections.sort(verbs, new VerbOrdering()); // we need to group the operations within the same tag, so use the path as default if not // configured String pathAsTag = rest.getTag() != null ? rest.getTag() : FileUtil.stripLeadingSeparator(rest.getPath()); String summary = rest.getDescriptionText(); if (ObjectHelper.isNotEmpty(pathAsTag)) { // add rest as tag Tag tag = new Tag(); tag.description(summary); tag.name(pathAsTag); swagger.addTag(tag); } // gather all types in use Set<String> types = new LinkedHashSet<>(); for (VerbDefinition verb : verbs) { String type = verb.getType(); if (ObjectHelper.isNotEmpty(type)) { if (type.endsWith("[]")) { type = type.substring(0, type.length() - 2); } types.add(type); } type = verb.getOutType(); if (ObjectHelper.isNotEmpty(type)) { if (type.endsWith("[]")) { type = type.substring(0, type.length() - 2); } types.add(type); } // there can also be types in response messages if (verb.getResponseMsgs() != null) { for (RestOperationResponseMsgDefinition def : verb.getResponseMsgs()) { type = def.getResponseModel(); if (ObjectHelper.isNotEmpty(type)) { if (type.endsWith("[]")) { type = type.substring(0, type.length() - 2); } types.add(type); } } } } // use annotation scanner to find models (annotated classes) for (String type : types) { Class<?> clazz = classResolver.resolveClass(type); appendModels(clazz, swagger); } // used during gathering of apis List<Path> paths = new ArrayList<>(); String basePath = rest.getPath(); for (VerbDefinition verb : verbs) { // the method must be in lower case String method = verb.asVerb().toLowerCase(Locale.US); // operation path is a key String opPath = SwaggerHelper.buildUrl(basePath, verb.getUri()); Operation op = new Operation(); if (ObjectHelper.isNotEmpty(pathAsTag)) { // group in the same tag op.addTag(pathAsTag); } // add id as vendor extensions op.getVendorExtensions().put("x-camelContextId", camelContextId); op.getVendorExtensions().put("x-routeId", verb.getRouteId()); Path path = swagger.getPath(opPath); if (path == null) { path = new Path(); paths.add(path); } path = path.set(method, op); String consumes = verb.getConsumes() != null ? verb.getConsumes() : rest.getConsumes(); if (consumes != null) { String[] parts = consumes.split(","); for (String part : parts) { op.addConsumes(part); } } String produces = verb.getProduces() != null ? verb.getProduces() : rest.getProduces(); if (produces != null) { String[] parts = produces.split(","); for (String part : parts) { op.addProduces(part); } } if (verb.getDescriptionText() != null) { op.summary(verb.getDescriptionText()); } for (RestOperationParamDefinition param : verb.getParams()) { Parameter parameter = null; if (param.getType().equals(RestParamType.body)) { parameter = new BodyParameter(); } else if (param.getType().equals(RestParamType.form)) { parameter = new FormParameter(); } else if (param.getType().equals(RestParamType.header)) { parameter = new HeaderParameter(); } else if (param.getType().equals(RestParamType.path)) { parameter = new PathParameter(); } else if (param.getType().equals(RestParamType.query)) { parameter = new QueryParameter(); } if (parameter != null) { parameter.setName(param.getName()); parameter.setAccess(param.getAccess()); parameter.setDescription(param.getDescription()); parameter.setRequired(param.getRequired()); // set type on parameter if (parameter instanceof SerializableParameter) { SerializableParameter sp = (SerializableParameter) parameter; if (param.getDataType() != null) { sp.setType(param.getDataType()); } if (param.getAllowableValues() != null) { sp.setEnum(param.getAllowableValues()); } } // set schema on body parameter if (parameter instanceof BodyParameter) { BodyParameter bp = (BodyParameter) parameter; if (verb.getType() != null) { String ref = modelTypeAsRef(verb.getType(), swagger); if (ref != null) { bp.setSchema(new RefModel(ref)); } } } op.addParameter(parameter); } } // if we have an out type then set that as response message if (verb.getOutType() != null) { Response response = new Response(); Property prop = modelTypeAsProperty(verb.getOutType(), swagger); response.setSchema(prop); response.setDescription("Output type"); op.addResponse("200", response); } // enrich with configured response messages from the rest-dsl for (RestOperationResponseMsgDefinition msg : verb.getResponseMsgs()) { Response response = null; if (op.getResponses() != null) { response = op.getResponses().get(msg.getCode()); } if (response == null) { response = new Response(); } if (ObjectHelper.isNotEmpty(msg.getResponseModel())) { Property prop = modelTypeAsProperty(msg.getResponseModel(), swagger); response.setSchema(prop); } response.setDescription(msg.getMessage()); op.addResponse(msg.getCode(), response); } // add path swagger.path(opPath, path); } }