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.xbean.spring.generator;
018
019import java.io.File;
020import java.io.FileWriter;
021import java.io.IOException;
022import java.io.PrintWriter;
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Map.Entry;
029
030/**
031 * @author Hiram Chirino
032 * @version $Id$
033 * @since 1.0
034 */
035public 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