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     */
017    package org.apache.xbean.spring.generator;
018    
019    import java.io.File;
020    import java.io.FileWriter;
021    import java.io.IOException;
022    import java.io.PrintWriter;
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.HashMap;
026    import java.util.Iterator;
027    import java.util.Map;
028    import java.util.Map.Entry;
029    
030    /**
031     * @author Hiram Chirino
032     * @version $Id$
033     * @since 1.0
034     */
035    public class WikiDocumentationGenerator implements GeneratorPlugin {
036        private final File destFile;
037        private LogFacade log;
038    
039        public WikiDocumentationGenerator(File destFile) {
040            this.destFile = destFile;
041        }
042    
043        public void generate(NamespaceMapping namespaceMapping) throws IOException {
044            String namespace = namespaceMapping.getNamespace();
045            File file = new File(destFile.getParentFile(), destFile.getName() + ".wiki");
046            log.log("Generating WIKI documentation file: " + file + " for namespace: " + namespace);
047            PrintWriter out = new PrintWriter(new FileWriter(file));
048            try {
049                generateDocumentation(out, namespaceMapping);
050            } finally {
051                out.close();
052            }
053        }
054    
055        private void generateDocumentation(PrintWriter out, NamespaceMapping namespaceMapping) {
056            HashMap refercencedTypes = new HashMap();
057            
058            // Build of map of types that are referenced by element types. 
059            for (Iterator iter = namespaceMapping.getElements().iterator(); iter.hasNext();) {
060                ElementMapping element = (ElementMapping) iter.next();
061                for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
062                    AttributeMapping attribute = (AttributeMapping) iterator.next();
063                    Type type = getNestedType( attribute.getType() );
064                                    
065                    if( namespaceMapping.isSimpleType( type) )
066                        continue;
067                                    
068                    if( !refercencedTypes.containsKey(type.getName()) )
069                        refercencedTypes.put(type.getName(), new ArrayList());
070                }
071            }
072            
073            // Add all the elements that implement those types.
074            for (Iterator iter = refercencedTypes.entrySet().iterator(); iter.hasNext();) {
075                    
076                Map.Entry entry = (Map.Entry) iter.next();
077                String type = (String) entry.getKey();
078                ArrayList implementations = (ArrayList) entry.getValue();
079    
080                for (Iterator iterator = namespaceMapping.getElements().iterator(); iterator.hasNext();) {
081                    ElementMapping element = (ElementMapping) iterator.next();
082                        
083                    // Check to see if the class is matches
084                    boolean matched=false;
085                    if (type.equals(element.getClassName())) {
086                        implementations.add(element);
087                        matched=true;
088                    }
089                        
090                    // Perhaps a super class matches.
091                    if(!matched) {
092                        for (Iterator j = element.getSuperClasses().iterator(); j.hasNext();) {
093                            String t = (String) j.next();
094                            if( type.equals(t) ) {
095                                implementations.add(element);
096                                matched=true;
097                                break;
098                            }
099                        }
100                    }
101                        
102                    // Or it might be an interface.
103                    if(!matched) {
104                        for (Iterator j = element.getInterfaces().iterator(); j.hasNext();) {
105                            String t = (String) j.next();
106                            if( type.equals(t) ) {
107                                implementations.add(element);
108                                matched=true;
109                                break;
110                            }
111                        }
112                    }
113                }
114            }
115            
116            // Remove any entries that did not have associated elements
117            for (Iterator iter = refercencedTypes.values().iterator(); iter.hasNext();) {           
118                ArrayList implementations = (ArrayList) iter.next();
119                if( implementations.isEmpty() )
120                    iter.remove();
121            }        
122    
123            generateElementsByType(out, namespaceMapping, refercencedTypes);
124            generateElementsDetail(out, namespaceMapping, refercencedTypes);
125            generateElementsIndex(out, namespaceMapping, refercencedTypes);
126        }
127    
128        private Type getNestedType(Type type) {
129            if( type.isCollection() ) {
130                return getNestedType(type.getNestedType());
131            } else {
132                return type;
133            }
134        }
135        
136        private void generateElementsByType(PrintWriter out, NamespaceMapping namespaceMapping, HashMap refercencedTypes) {
137            out.println("h3. Elements By Type");
138            for (Iterator iter = refercencedTypes.entrySet().iterator(); iter.hasNext();) {
139                Entry entry = (Entry) iter.next();
140                String className = (String) entry.getKey();
141                Collection elements = (Collection) entry.getValue();
142    
143                out.println("{anchor:"+className+"-types}");
144                out.println("h4. The _["+className+"|#"+className+"-types]_ Type Implementations");
145    
146                for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
147                    ElementMapping element = (ElementMapping) iterator.next();
148                    out.println("    | _[<"+element.getElementName() +">|#"+element.getElementName() +"-element]_ | {html}"+element.getDescription()+"{html} |");
149                }
150                out.println();              
151            }
152            out.println();
153        }
154    
155            private void generateElementsIndex(PrintWriter out, NamespaceMapping namespaceMapping, HashMap refercencedTypes) {
156            
157            out.println("h3. Element Index");
158            for (Iterator iter = namespaceMapping.getElements().iterator(); iter.hasNext();) {
159                ElementMapping element = (ElementMapping) iter.next();
160                    out.println("    | _[<"+element.getElementName() +">|#"+element.getElementName() +"-element]_ | {html}"+element.getDescription()+"{html} |");
161            }
162            out.println();
163        }
164    
165        private void generateElementsDetail(PrintWriter out, NamespaceMapping namespaceMapping, HashMap refercencedTypes) {
166            for (Iterator iter = namespaceMapping.getElements().iterator(); iter.hasNext();) {
167                ElementMapping element = (ElementMapping) iter.next();
168                generateElementDetail(out, namespaceMapping, element, refercencedTypes);
169            }
170        }
171    
172        private void generateElementDetail(PrintWriter out, NamespaceMapping namespaceMapping, ElementMapping element, HashMap refercencedTypes) {    
173    
174            out.println("{anchor:" + element.getElementName() + "-element}");
175            out.println("h3. The _[<" + element.getElementName() + ">|#" + element.getElementName() + "-element]_ Element");
176    
177            out.println("    {html}"+element.getDescription()+"{html}");
178    
179            if( element.getAttributes().size() > 0 ) {
180                out.println("h4. Properties");
181                out.println("    || Property Name || Type || Description ||");
182    
183                for ( Iterator iterator = element.getAttributes().iterator(); iterator.hasNext(); ) {
184                    AttributeMapping attribute = (AttributeMapping) iterator.next();
185                    Type type = attribute.getPropertyEditor() != null ? Type.newSimpleType(String.class.getName()): attribute.getType();
186                    out.println("    | " + attribute.getAttributeName() + " | "+getTypeLink(type, refercencedTypes)+" | {html}"+attribute.getDescription()+"{html} |");     
187                      }
188            }
189            out.println();
190        }
191    
192        private String getTypeLink(Type type, HashMap refercencedTypes) {
193            if (type.isCollection()) {
194                return "(" + getTypeLink(type.getNestedType(), refercencedTypes) +  ")\\*";
195            } else {
196                      if( refercencedTypes.containsKey(type.getName()) ) {
197                                return "_["+type.getName()+"|#"+type.getName()+"-types]_";
198                      } else {
199                    return "_"+type.getName()+"_";
200                }
201            }        
202        }
203    
204        public LogFacade getLog() {
205            return log;
206        }
207    
208        public void setLog(LogFacade log) {
209            this.log = log;
210        }
211    }
212