/** * Enrich portClassHier with class/interface names that map to a list of parent * classes/interfaces. For any class encountered, find its parents too.<br> * Also find the port types which have assignable schema classes. * * @param oper Operator to work on * @param portClassHierarchy In-Out param that contains a mapping of class/interface to its * parents * @param portTypesWithSchemaClasses Json that will contain all the ports which have any schema * classes. */ public void buildAdditionalPortInfo( JSONObject oper, JSONObject portClassHierarchy, JSONObject portTypesWithSchemaClasses) { try { JSONArray ports = oper.getJSONArray(OperatorDiscoverer.PORT_TYPE_INFO_KEY); for (int i = 0; i < ports.length(); i++) { JSONObject port = ports.getJSONObject(i); String portType = port.optString("type"); if (portType == null) { // skipping if port type is null continue; } if (typeGraph.size() == 0) { buildTypeGraph(); } try { // building port class hierarchy LinkedList<String> queue = Lists.newLinkedList(); queue.add(portType); while (!queue.isEmpty()) { String currentType = queue.remove(); if (portClassHierarchy.has(currentType)) { // already present in the json so we skip. continue; } List<String> immediateParents = typeGraph.getParents(currentType); if (immediateParents == null) { portClassHierarchy.put(currentType, Lists.<String>newArrayList()); continue; } portClassHierarchy.put(currentType, immediateParents); queue.addAll(immediateParents); } } catch (JSONException e) { LOG.warn("building port type hierarchy {}", portType, e); } // finding port types with schema classes if (portTypesWithSchemaClasses.has(portType)) { // already present in the json so skipping continue; } if (portType.equals("byte") || portType.equals("short") || portType.equals("char") || portType.equals("int") || portType.equals("long") || portType.equals("float") || portType.equals("double") || portType.equals("java.lang.String") || portType.equals("java.lang.Object")) { // ignoring primitives, strings and object types as this information is needed only for // complex types. continue; } if (port.has("typeArgs")) { // ignoring any type with generics continue; } boolean hasSchemaClasses = false; List<String> instantiableDescendants = typeGraph.getInstantiableDescendants(portType); if (instantiableDescendants != null) { for (String descendant : instantiableDescendants) { try { if (typeGraph.isInstantiableBean(descendant)) { hasSchemaClasses = true; break; } } catch (JSONException ex) { LOG.warn("checking descendant is instantiable {}", descendant); } } } portTypesWithSchemaClasses.put(portType, hasSchemaClasses); } } catch (JSONException e) { // should not reach this LOG.error("JSON Exception {}", e); throw new RuntimeException(e); } }
public JSONObject describeOperator(String clazz) throws Exception { TypeGraphVertex tgv = typeGraph.getTypeGraphVertex(clazz); if (tgv.isInstantiable()) { JSONObject response = new JSONObject(); JSONArray inputPorts = new JSONArray(); JSONArray outputPorts = new JSONArray(); // Get properties from ASM JSONObject operatorDescriptor = describeClassByASM(clazz); JSONArray properties = operatorDescriptor.getJSONArray("properties"); properties = enrichProperties(clazz, properties); JSONArray portTypeInfo = operatorDescriptor.getJSONArray("portTypeInfo"); List<CompactFieldNode> inputPortfields = typeGraph.getAllInputPorts(clazz); List<CompactFieldNode> outputPortfields = typeGraph.getAllOutputPorts(clazz); try { for (CompactFieldNode field : inputPortfields) { JSONObject inputPort = setFieldAttributes(clazz, field); if (!inputPort.has("optional")) { inputPort.put( "optional", false); // input port that is not annotated is default to be not optional } if (!inputPort.has(SCHEMA_REQUIRED_KEY)) { inputPort.put(SCHEMA_REQUIRED_KEY, false); } inputPorts.put(inputPort); } for (CompactFieldNode field : outputPortfields) { JSONObject outputPort = setFieldAttributes(clazz, field); if (!outputPort.has("optional")) { outputPort.put( "optional", true); // output port that is not annotated is default to be optional } if (!outputPort.has("error")) { outputPort.put("error", false); } if (!outputPort.has(SCHEMA_REQUIRED_KEY)) { outputPort.put(SCHEMA_REQUIRED_KEY, false); } outputPorts.put(outputPort); } response.put("name", clazz); response.put("properties", properties); response.put(PORT_TYPE_INFO_KEY, portTypeInfo); response.put("inputPorts", inputPorts); response.put("outputPorts", outputPorts); OperatorClassInfo oci = classInfo.get(clazz); if (oci != null) { if (oci.comment != null) { String[] descriptions; // first look for a <p> tag String keptPrefix = "<p>"; descriptions = oci.comment.split("<p>", 2); if (descriptions.length == 0) { keptPrefix = ""; // if no <p> tag, then look for a blank line descriptions = oci.comment.split("\n\n", 2); } if (descriptions.length > 0) { response.put("shortDesc", descriptions[0]); } if (descriptions.length > 1) { response.put("longDesc", keptPrefix + descriptions[1]); } } response.put("category", oci.tags.get("@category")); String displayName = oci.tags.get("@displayName"); if (displayName == null) { displayName = decamelizeClassName(ClassUtils.getShortClassName(clazz)); } response.put("displayName", displayName); String tags = oci.tags.get("@tags"); if (tags != null) { JSONArray tagArray = new JSONArray(); for (String tag : StringUtils.split(tags, ',')) { tagArray.put(tag.trim().toLowerCase()); } response.put("tags", tagArray); } String doclink = oci.tags.get("@doclink"); if (doclink != null) { response.put("doclink", doclink + "?" + getDocName(clazz)); } else if (clazz.startsWith("com.datatorrent.lib.") || clazz.startsWith("com.datatorrent.contrib.")) { response.put("doclink", DT_OPERATOR_DOCLINK_PREFIX + "?" + getDocName(clazz)); } } } catch (JSONException ex) { throw new RuntimeException(ex); } return response; } else { throw new UnsupportedOperationException(); } }