001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.openwire.tool;
018
019import java.io.File;
020import java.io.PrintWriter;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.Comparator;
024import java.util.HashMap;
025import java.util.Iterator;
026import java.util.LinkedHashMap;
027import java.util.List;
028
029import org.codehaus.jam.JAnnotation;
030import org.codehaus.jam.JAnnotationValue;
031import org.codehaus.jam.JClass;
032import org.codehaus.jam.JProperty;
033
034/**
035 * 
036 */
037public class CHeadersGenerator extends SingleSourceGenerator {
038
039    protected String targetDir = "./src/lib/openwire";
040
041    public Object run() {
042        filePostFix = ".h";
043        if (destFile == null) {
044            destFile = new File(targetDir + "/ow_commands_v" + getOpenwireVersion() + ".h");
045        }
046        return super.run();
047    }
048
049    public String getTargetDir() {
050        return targetDir;
051    }
052
053    public void setTargetDir(String targetDir) {
054        this.targetDir = targetDir;
055    }
056
057    protected void generateLicence(PrintWriter out) {
058        out.println("/**");
059        out.println(" * Licensed to the Apache Software Foundation (ASF) under one or more");
060        out.println(" * contributor license agreements.  See the NOTICE file distributed with");
061        out.println(" * this work for additional information regarding copyright ownership.");
062        out.println(" * The ASF licenses this file to You under the Apache License, Version 2.0");
063        out.println(" * (the \"License\"); you may not use this file except in compliance with");
064        out.println(" * the License.  You may obtain a copy of the License at");
065        out.println(" *");
066        out.println(" *      http://www.apache.org/licenses/LICENSE-2.0");
067        out.println(" *");
068        out.println(" * Unless required by applicable law or agreed to in writing, software");
069        out.println(" * distributed under the License is distributed on an \"AS IS\" BASIS,");
070        out.println(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
071        out.println(" * See the License for the specific language governing permissions and");
072        out.println(" * limitations under the License.");
073        out.println(" */");
074    }
075
076    String changeCase(String value) {
077        StringBuffer b = new StringBuffer();
078        char[] cs = value.toCharArray();
079        for (int i = 0; i < cs.length; i++) {
080            char c = cs[i];
081            if (Character.isUpperCase((char)c)) {
082                b.append('_');
083                b.append(Character.toLowerCase((char)c));
084            } else {
085                b.append(c);
086            }
087        }
088        return b.toString();
089    }
090
091    String toPropertyCase(String value) {
092        return value.substring(0, 1).toLowerCase() + value.substring(1);
093    }
094
095    /**
096     * Sort the class list so that base classes come up first.
097     */
098    protected List<JClass> sort(List source) {
099        LinkedHashMap<JClass, JClass> rc = new LinkedHashMap<JClass, JClass>();
100        ArrayList classes = new ArrayList(source);
101        Collections.sort(classes, new Comparator() {
102            public int compare(Object o1, Object o2) {
103                JClass c1 = (JClass)o1;
104                JClass c2 = (JClass)o2;
105                return c1.getSimpleName().compareTo(c2.getSimpleName());
106            }
107        });
108
109        // lets make a map of all the class names
110        HashMap<JClass, JClass> classNames = new HashMap<JClass, JClass>();
111        for (Iterator iter = classes.iterator(); iter.hasNext();) {
112            JClass c = (JClass)iter.next();
113            classNames.put(c, c);
114        }
115
116        // Add all classes that have no parent first
117        for (Iterator iter = classes.iterator(); iter.hasNext();) {
118            JClass c = (JClass)iter.next();
119            if (!classNames.containsKey(c.getSuperclass())) {
120                rc.put(c, c);
121            }
122        }
123
124        // now lets add the rest
125        for (Iterator iter = classes.iterator(); iter.hasNext();) {
126            JClass c = (JClass)iter.next();
127            if (!rc.containsKey(c)) {
128                rc.put(c, c);
129            }
130        }
131
132        return new ArrayList<JClass>(rc.keySet());
133    }
134
135    void generateFields(PrintWriter out, JClass jclass) {
136
137        if (jclass.getSuperclass() == null || jclass.getSuperclass().getSimpleName().equals("Object")) {
138            out.println("");
139            out.println("   ow_byte structType;");
140        } else {
141            generateFields(out, jclass.getSuperclass());
142        }
143
144        ArrayList<JProperty> properties = new ArrayList<JProperty>();
145        jclass.getDeclaredProperties();
146        for (int i = 0; i < jclass.getDeclaredProperties().length; i++) {
147            JProperty p = jclass.getDeclaredProperties()[i];
148            if (isValidProperty(p)) {
149                properties.add(p);
150            }
151        }
152        for (Iterator<JProperty> iter = properties.iterator(); iter.hasNext();) {
153            JProperty property = iter.next();
154            JAnnotation annotation = property.getGetter().getAnnotation("openwire:property");
155//            JAnnotationValue size = annotation.getValue("size");
156            String name = toPropertyCase(property.getSimpleName());
157//            boolean cached = isCachedProperty(property);
158
159            String type = property.getType().getQualifiedName();
160            if (type.equals("boolean")) {
161                out.println("   ow_" + type + " " + name + ";");
162            } else if (type.equals("byte")) {
163                out.println("   ow_" + type + " " + name + ";");
164            } else if (type.equals("char")) {
165                out.println("   ow_" + type + " " + name + ";");
166            } else if (type.equals("short")) {
167                out.println("   ow_" + type + " " + name + ";");
168            } else if (type.equals("int")) {
169                out.println("   ow_" + type + " " + name + ";");
170            } else if (type.equals("long")) {
171                out.println("   ow_" + type + " " + name + ";");
172            } else if (type.equals("byte[]")) {
173                out.println("   ow_byte_array *" + name + ";");
174            } else if (type.equals("org.apache.activeio.packet.ByteSequence")) {
175                out.println("   ow_byte_array *" + name + ";");
176            } else if (type.equals("org.apache.activeio.packet.ByteSequence")) {
177                out.println("   ow_byte_array *" + name + ";");
178            } else if (type.equals("java.lang.String")) {
179                out.println("   ow_string *" + name + ";");
180            } else {
181                if (property.getType().isArrayType()) {
182                    out.println("   ow_DataStructure_array *" + name + ";");
183                } else if (isThrowable(property.getType())) {
184                    out.println("   ow_throwable *" + name + ";");
185                } else {
186                    out.println("   struct ow_" + property.getType().getSimpleName() + " *" + name + ";");
187                }
188            }
189        }
190    }
191
192    protected void generateSetup(PrintWriter out) {
193        generateLicence(out);
194        out.println("");
195        out.println("/*****************************************************************************************");
196        out.println(" *  ");
197        out.println(" * NOTE!: This file is auto generated - do not modify!");
198        out.println(" *        if you need to make a change, please see the modify the groovy scripts in the");
199        out.println(" *        under src/gram/script and then use maven openwire:generate to regenerate ");
200        out.println(" *        this file.");
201        out.println(" *  ");
202        out.println(" *****************************************************************************************/");
203        out.println(" ");
204        out.println("#ifndef OW_COMMANDS_V" + openwireVersion + "_H");
205        out.println("#define OW_COMMANDS_V" + openwireVersion + "_H");
206        out.println("");
207        out.println("#include \"ow.h\"");
208        out.println("");
209        out.println("#ifdef __cplusplus");
210        out.println("extern \"C\" {");
211        out.println("#endif /* __cplusplus */");
212        out.println("      ");
213        out.println("#define OW_WIREFORMAT_VERSION " + openwireVersion + "");
214
215        out.println("#define OW_WIREFORMAT_STACK_TRACE_MASK     0x00000001;");
216        out.println("#define OW_WIREFORMAT_TCP_NO_DELAY_MASK    0x00000002;");
217        out.println("#define OW_WIREFORMAT_CACHE_MASK           0x00000004;");
218        out.println("#define OW_WIREFORMAT_COMPRESSION_MASK     0x00000008;");
219
220        for (Iterator iterator = sortedClasses.iterator(); iterator.hasNext();) {
221            JClass jclass = (JClass)iterator.next();
222            String name = jclass.getSimpleName();
223            String type = ("ow_" + name).toUpperCase() + "_TYPE";
224            if (!isAbstract(jclass)) {
225                out.println("#define " + type + " " + getOpenWireOpCode(jclass));
226            }
227        }
228
229        out.println("      ");
230        out.println("apr_status_t ow_bitmarshall(ow_bit_buffer *buffer, ow_DataStructure *object);");
231        out.println("apr_status_t ow_marshall(ow_byte_buffer *buffer, ow_DataStructure *object);");
232    }
233
234    protected void generateFile(PrintWriter out) throws Exception {
235
236        String structName = jclass.getSimpleName();
237
238        out.println("");
239        out.println("typedef struct ow_" + structName + " {");
240
241        // This recusivly generates the field definitions of the class and it's
242        // supper classes.
243        generateFields(out, jclass);
244
245        out.println("");
246        out.println("} ow_" + structName + ";");
247        out.println("ow_" + structName + " *ow_" + structName + "_create(apr_pool_t *pool);");
248        out.println("ow_boolean ow_is_a_" + structName + "(ow_DataStructure *object);");
249
250    }
251
252    protected void generateTearDown(PrintWriter out) {
253        out.println("");
254        out.println("#ifdef __cplusplus");
255        out.println("}");
256        out.println("#endif");
257        out.println("");
258        out.println("#endif  /* ! OW_COMMANDS_V" + openwireVersion + "_H */");
259    }
260}