diff options
Diffstat (limited to 'sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/cpp/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/services/ComponentDomNodeHandler.java')
-rw-r--r-- | sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/cpp/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/services/ComponentDomNodeHandler.java | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/cpp/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/services/ComponentDomNodeHandler.java b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/cpp/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/services/ComponentDomNodeHandler.java new file mode 100644 index 0000000000..28974b41a6 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/cpp/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/services/ComponentDomNodeHandler.java @@ -0,0 +1,366 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* @version $Rev$ $Date$ */ + +package org.apache.tuscany.sca.cpp.tools.services; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.cpp.tools.common.Headers; +import org.apache.tuscany.sca.cpp.tools.common.Signature; +import org.apache.tuscany.sca.cpp.tools.common.Utils; +import org.w3c.dom.Node; + +/** + * This class will do the required processing for the <component>element of a + * sca composite file. + */ +public class ComponentDomNodeHandler extends GenericDomNodeHandler { + + /** + * This method will do the "normal" processing and then trigger a call to + * processComponentNode. + * + * @param node + * the node being processed + * @param contextXPath + * the XPath to the node + * @param handlers + * the map pf element names to DomNodeHandlers + * @param parameters + * a map of XPaths to parameters values found so far + */ + + public void handleNode(Node node, String contextXPath, Map handlers, + Map parameters) { + + // Pick up attrs and the interface.cpp child elements + super.handleNode(node, contextXPath, handlers, parameters); + + try { + //OK now go and create the wrapper and proxy for the service + processComponentNode(contextXPath, parameters); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * This method basically moved from the text names of things to operating on + * the actual Files. It will also verify or work out the correct class name + * for the implmentation and complain if this does match at least one + * potential service method in the class. + * + * @param contextXPath + * used to pull the correct values from the parameters map (as + * there can be multiple implementation.cpp elelements in there). + * @param parameters + * a map of XPath keys to attribute values + * @throws Exception + */ + private void processComponentNode(String contextXPath, Map parameters) + throws Exception { + + String implHeader = (String) parameters.get(contextXPath + + "/implementation.cpp/@header"); + String implClass = (String) parameters.get(contextXPath + + "/implementation.cpp/@class"); + + File compositeOrFragmentFile = (File) parameters + .get("compositeOrFragmentFile"); + File implHeaderFile = null; + if (null != compositeOrFragmentFile) { + File dir = compositeOrFragmentFile.getParentFile(); + implHeaderFile = new File(dir, implHeader); + } else { + throw new InternalError( + "Internal error: composite or fragment file not present in internal parameters"); + } + + try { + String resolvedImplClassName = getClassName(implHeaderFile, + implClass); + + // Check or retrieve the impl Class name. + if (null == resolvedImplClassName) { + try { + //A class attribute was set but there were no methods of + // the + // class in the header + System.out + .println("Classname given (" + + implClass + + ") does not match any header file method's classes in file: " + + implHeaderFile.getCanonicalPath()); + } catch (IOException e) { + System.out + .println("Classname given (" + + implClass + + ") does not match any header file method's classes in file: " + + implHeaderFile.getAbsolutePath()); + } + return; + } else { + File target = (File) parameters.get("targetFile"); + // go into the .componentType file and generate the cpp + processComponentTypeFile(implHeaderFile, target, + resolvedImplClassName); + + } + } catch (Exception e) { + String compName = (String) parameters + .get("/compositeFragment/component/@name"); + Utils + .screenMessage("Problem interpreting header or class attributes in " + + compName + + " component, in " + + compositeOrFragmentFile.getPath() + " file"); + System.exit(-2); + } + + } + + /** + * The purpose of this method is to move from the DOM parameters to dealing + * with the actual Files involved. It is from this method that we kick off + * the processing of the componentType file. + * + * @param header + * the implementation header + * @param target + * the directory for the output + * @param implClass + * @throws Exception + */ + private void processComponentTypeFile(File header, File target, + String implClass) throws Exception { + + // The componentType files should be in the same dir as the Impl + // header... + if (header == null || target == null) { + return; + } + + File componentTypeDirectory = header.getParentFile(); + String headerFileName = header.getName(); + String componentTypeName = headerFileName.substring(0, headerFileName + .lastIndexOf(".")); + + File componentTypeFile = new File(componentTypeDirectory, + componentTypeName + ".componentType"); + + ComponentTypeFileHandler ctParser = new ComponentTypeFileHandler(); + + // The implClass is used in the generated wrapper code so we need to + // store + // it so we can tunnel through the standard actOnFile signature. + + int namespaceEnd = -1; + if (null != implClass) { + namespaceEnd = implClass.lastIndexOf("::"); + } + + String namespace = null; + + if (-1 != namespaceEnd) { + namespace = implClass.substring(0, namespaceEnd); + ctParser.setParameter("implNamespace", namespace); + implClass = implClass.substring(namespaceEnd + 2); + } + + if (implClass != null) { + ctParser.setParameter("implClass", implClass); + } + + try { + ctParser.handleComponentTypeFile(componentTypeFile, target); + } catch (Exception e) { + Utils + .screenMessage("There has been a problem parsing the componentType file: " + + componentTypeFile.getCanonicalPath()); + Utils.screenMessage(" the reported errors is " + + e.getLocalizedMessage()); + Utils.screenMessage(" and the java exception stack is below."); + e.printStackTrace(); + throw e; + } + } + + /** + * The resolve and check the classname of the service. If we have an + * implementation class name we have to check that there is: at least one + * (non-private, non constructor or finalizer) method of that class in the + * header If there is no implementation class then we will return the class + * of the first non-private/constructor/finalizer method we find. + * + * @param header + * @param implementationCppClass + * @return + * @throws Exception + */ + private String getClassName(File header, String implementationCppClass) + throws Exception { + String methodClassName = null; + List methods = null; + + if (null == header) { + return null; + } + + Utils.postEvent(Utils.DEPLOYMENT_ARTEFACT_ENCOUNTERED, header + .getAbsolutePath()); + Utils.postEvent(Utils.EVENT_TYPE_FILE_PARSED, + "Scagen processing C++ implementation header " + + header.getAbsolutePath()); + + try { + Headers headers = new Headers(); + + headers.actOnFile(header, null, 1); + + methods = headers.getAllMethods(); + + } catch (FileNotFoundException fnfe) { + String path; + try { + path = header.getCanonicalPath(); + } catch (IOException e1) { + path = header.getPath(); + } + Utils.screenMessage("The header file: " + path + + " referenced cannot be found."); + throw fnfe; + } catch (Exception e) { + String path = header.getPath(); + Utils.screenMessage("The header file: " + path + + " referenced is not valid. Reason given is " + + e.getLocalizedMessage()); + throw e; + } + + // We need at least some methods + if (null == methods) { + return null; + } + + // We need at least one service method of to do anything + methods = trimMethodsOfPrivatesConstructorsAndDestrutors(methods); + if (null == methods || methods.size() == 0) { + return null; + } + + // If the user specifies an implementation class then we need at + // least one service method of that class + if (implementationCppClass != null) { + methods = filterMethodsToOneClass(methods, implementationCppClass); + + if (null == methods || methods.size() == 0) { + return null; + } else { + // There was at least one method of the correct type + return implementationCppClass; + } + } else { + // Implementation class is null so we return the fully qualified classname of the + // first service method + Signature s = (Signature) methods.get(0); + String className = s.getTrimClassName(); + String namespace = s.getNamespace(); + if( namespace != null && namespace.length() > 0) + { + className = namespace + "::" + className; + } + + return className; + } + } + + /** + * Filter the mthods supplied to only ones fo the supplied class. + * + * @param methods + * the list of methods + * @param implementationCppClass + * the class we wish + * @return a list of methods of the correct class + */ + private List filterMethodsToOneClass(List methods, + String implementationCppClass) { + + if (null == methods) { + return null; + } + + if (null == implementationCppClass + || implementationCppClass.length() == 0) { + return null; + } + + for (Iterator iter = methods.listIterator(); iter.hasNext();) { + Signature method = (Signature) iter.next(); + + String className = method.getTrimClassName(); + String namespace = method.getNamespace(); + + if (namespace != null && namespace.length() > 0) { + className = namespace + "::" + className; + } + + if (!implementationCppClass.equals(className)) { + iter.remove(); + } + } + + return methods; + + } + + /** + * This method removes contructor and destructor methods from the list. + * + * @param methods + * the list of methods + * @return + */ + private List trimMethodsOfPrivatesConstructorsAndDestrutors(List methods) { + + if (null == methods) { + return null; + } + + for (Iterator iter = methods.listIterator(); iter.hasNext();) { + Signature method = (Signature) iter.next(); + + if (method.isConstructor() || method.isDestructor()) { + iter.remove(); + } + } + + return methods; + } + +} |