001    package com.hammurapi.render.emf;
002    
003    import java.io.File;
004    import java.util.ArrayList;
005    import java.util.HashMap;
006    import java.util.IdentityHashMap;
007    import java.util.List;
008    import java.util.Locale;
009    import java.util.Map;
010    
011    import org.apache.tools.ant.BuildException;
012    import org.apache.tools.ant.Task;
013    import org.eclipse.emf.common.util.TreeIterator;
014    import org.eclipse.emf.common.util.URI;
015    import org.eclipse.emf.ecore.EClassifier;
016    import org.eclipse.emf.ecore.EObject;
017    import org.eclipse.emf.ecore.EPackage;
018    import org.eclipse.emf.ecore.resource.Resource;
019    import org.eclipse.emf.ecore.resource.ResourceSet;
020    import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
021    import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
022    import org.eclipse.gmf.runtime.notation.Diagram;
023    import org.eclipse.gmf.runtime.notation.NotationPackage;
024    
025    import com.hammurapi.common.Context;
026    import com.hammurapi.common.DefaultContext;
027    import com.hammurapi.common.IdentityManager;
028    import com.hammurapi.render.RenderingConstants;
029    import com.hammurapi.render.RenderingException;
030    import com.hammurapi.render.ReportGenerator;
031    
032    /**
033     * Generates HTML documentation for ECore models and diagrams.
034     * @author Pavel Vlasov
035     *
036     */
037    public class EcoreDoc extends Task {
038            
039            @Override
040            public void execute() throws BuildException {
041                    long start = System.currentTimeMillis();
042    
043                    if (outputDir==null && outputFile==null) {
044                            throw new BuildException("Either outputdir or outputfile must be set.");
045                    }
046                    
047                    if (outputDir!=null && !outputDir.exists()) {
048                            outputDir.mkdirs();
049                    }
050                    
051                    ResourceSet resourceSet = new ResourceSetImpl();
052                    
053                    resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
054                                    Resource.Factory.Registry.DEFAULT_EXTENSION, 
055                                    new XMIResourceFactoryImpl());
056                    
057                    resourceSet.getPackageRegistry().put(NotationPackage.eNS_URI, NotationPackage.eINSTANCE);               
058    
059                    File file = getProject()==null ? new File(diagram) : new File(getProject().getBaseDir(), diagram);
060                    URI uri = file.isFile() ? URI.createFileURI(file.getAbsolutePath()): URI.createURI(diagram);
061                                    
062                    Resource resource = resourceSet.getResource(uri, true);
063                    
064                    Model model = new Model();
065                    
066                    ReportGenerator generator = new ReportGenerator();
067                    
068                    Map<String, Object> env = new HashMap<String, Object>();
069                    env.put(RenderingConstants.RENDER_START, start);
070                    Context context = new DefaultContext(EcoreDoc.class.getClassLoader(), null);
071                    IdentityManager<?> identityManager = context.lookup(IdentityManager.class);
072                    env.put(RenderingConstants.RENDER_HELPER, new ModelRenderHelper(identityManager, outputDir==null ? outputFile.getParentFile() : outputDir, diagramMap, model, env, context, locale, http));
073                    
074                    generator.setEnvironment(env);
075                    generator.setContext(context);
076                    
077                    for (EObject obj: resource.getContents()) {
078                            mapDiagram(obj);
079                            TreeIterator<EObject> it = obj.eAllContents();
080                            while (it.hasNext()) {
081                                    EObject next = it.next();
082                                    mapDiagram(next);
083                            }
084                    }
085                                    
086                    
087                    for (EObject obj: resource.getContents()) {
088                            if (obj instanceof Diagram) {
089                                    Diagram diagram = (Diagram) obj;
090                                                                    
091                                    EObject diagramElement = diagram.getElement();
092                                                                    
093                                    if (diagramElement instanceof EPackage) {                                       
094                                            EPackage pkg = (EPackage) diagramElement;
095                                            while (pkg.getESuperPackage()!=null) {
096                                                    pkg = pkg.getESuperPackage();
097                                            }
098                                            if (!model.getRootPackages().contains(pkg)) {                                           
099                                                    model.getRootPackages().add(pkg);
100                                            }
101                                    } else if (diagramElement instanceof EClassifier) {
102                                            EPackage pkg = ((EClassifier) diagramElement).getEPackage();
103                                            while (pkg.getESuperPackage()!=null) {
104                                                    pkg = pkg.getESuperPackage();
105                                            }
106                                            if (!model.getRootPackages().contains(pkg)) {                                           
107                                                    model.getRootPackages().add(pkg);
108                                            }                                       
109                                    }
110                                    model.getDiagrams().add(diagram);
111                            } else {
112                                    System.err.println("Unexpected contents: "+obj);
113                            }
114                    }
115                    
116                    try {
117                            if (outputDir==null) {
118                                    generator.generate(model, outputFile, "Model documentation", "onepage", http);                          
119                            } else {
120                                    generator.generate(model, outputDir, "Model documentation", http);
121                            }
122                    } catch (RenderingException e) {
123                            throw new BuildException(e);
124                    }
125            }
126            
127            private String diagram;
128            private File outputDir;
129            private File outputFile;
130            private Locale locale;
131            private boolean http;
132            
133            /**
134             * Sets rendering locale.
135             * @param locale
136             */
137            public void setLocale(Locale locale) {
138                    this.locale = locale;
139            }
140            
141            /**
142             * Source diagram - file or URL
143             * @return
144             */
145            public String getDiagram() {
146                    return diagram;
147            }
148    
149            /**
150             * Source diagram - file or URL
151             * @param diagram
152             */
153            public void setDiagram(String diagram) {
154                    this.diagram = diagram;
155            }
156    
157            /**
158             * Output directory
159             * @return
160             */
161            public File getOutputDir() {
162                    return outputDir;
163            }
164    
165            /**
166             * Output directory
167             * @param outputDir
168             */
169            public void setOutputDir(File outputDir) {
170                    if (outputFile!=null) {
171                            throw new BuildException("outputdir and outputfile are mutually exclusive");
172                    }
173                    this.outputDir = outputDir;
174            }
175            
176            public File getOutputFile() {
177                    return outputFile;
178            }
179    
180            /**
181             * If outputfile attribute is set, then the task generates documenation in a single HTML file. Convenient for printing.
182             * @param outputFile
183             */
184            public void setOutputFile(File outputFile) {
185                    if (outputDir!=null) {
186                            throw new BuildException("outputdir and outputfile are mutually exclusive");
187                    }
188                    this.outputFile = outputFile;
189            }
190    
191            public boolean isHttp() {
192                    return http;
193            }
194    
195            /**
196             * If true, outline and contents trees are rendered to use AJAX. It is useful for 
197             * large models, but works only over HTTP.
198             * @param http
199             */
200            public void setHttp(boolean http) {
201                    this.http = http;
202            }
203    
204            // Assigns ID's to elements for rendering.
205            private static Map<EObject, List<Diagram>> diagramMap = new IdentityHashMap<EObject, List<Diagram>>();
206    
207            /**
208             * Generates documentation from a diagram file.
209             * Command line parameters: &lt;diagram file&gt; &lt;output dir&gt; [http]
210             * @param args
211             */
212            public static void main(String[] args) throws Exception {
213                    System.out.println("Command line parameters: <diagram file> <output dir> [http]");
214                    System.out.println("Example: mymodel.ecorediag model-doc");
215                    
216                    EcoreDoc documenter = new EcoreDoc();
217                    documenter.setDiagram(args[0]);
218                    documenter.setOutputDir(new File(args[1]));
219                    documenter.setHttp(args.length>2 ? "http".equals(args[2]) : false);
220                    documenter.execute();
221            }
222    
223            private static void mapDiagram(EObject next) {
224                    if (next instanceof Diagram) {
225                            Diagram diagram = (Diagram) next;
226                            EObject diagramElement = diagram.getElement();
227                            if (diagramElement!=null) {
228                                    List<Diagram> diagrams = diagramMap.get(diagramElement);
229                                    if (diagrams == null) {
230                                            diagrams = new ArrayList<Diagram>();
231                                            diagramMap.put(diagramElement, diagrams);
232                                    }
233                                    diagrams.add(diagram);                                  
234                            }                                       
235                    }
236            }
237                    
238    }