summaryrefslogtreecommitdiffstats
path: root/tags/native-sca-1.0.incubating-M3/tools/scagen/src/org/apache/tuscany/sca/cpp/tools/services/ComponentDomNodeHandler.java
blob: 28974b41a6d0f45da52a46addd42f68be6ee1e75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
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;
    }

}