001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2007-2010 ADEQUATE SYSTEMS SARL
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.builder;
022    
023    import java.io.File;
024    import java.io.IOException;
025    import java.net.MalformedURLException;
026    import java.net.URL;
027    import java.net.URLClassLoader;
028    import java.util.ArrayList;
029    import java.util.Collections;
030    import java.util.HashMap;
031    import java.util.List;
032    import java.util.Map;
033    
034    import org.eclipse.core.resources.IProject;
035    import org.eclipse.core.runtime.CoreException;
036    import org.eclipse.jdt.core.IJavaProject;
037    import org.eclipse.jdt.core.JavaCore;
038    import org.granite.builder.properties.Gas3Classpath;
039    import org.granite.builder.properties.Gas3Project;
040    import org.granite.builder.properties.Gas3Source;
041    import org.granite.builder.properties.Gas3Translator;
042    import org.granite.builder.properties.GraniteProperties;
043    import org.granite.builder.properties.GranitePropertiesLoader;
044    import org.granite.builder.util.BuilderUtil;
045    import org.granite.builder.util.JavaClassInfo;
046    import org.granite.builder.util.ProjectUtil;
047    import org.granite.builder.util.ProjectUtil.CpEntry;
048    import org.granite.builder.util.ProjectUtil.CpEntry.CpeKind;
049    import org.granite.generator.Listener;
050    import org.granite.generator.TemplateUri;
051    import org.granite.generator.as3.As3TypeFactory;
052    import org.granite.generator.as3.DefaultAs3TypeFactory;
053    import org.granite.generator.as3.DefaultEntityFactory;
054    import org.granite.generator.as3.EntityFactory;
055    import org.granite.generator.as3.JavaAs3GroovyConfiguration;
056    import org.granite.generator.as3.JavaAs3Input;
057    import org.granite.generator.as3.PackageTranslator;
058    import org.granite.generator.as3.RemoteDestinationFactory;
059    import org.granite.generator.as3.reflect.JavaType.Kind;
060    import org.granite.generator.gsp.GroovyTemplateFactory;
061    
062    /**
063     * @author Franck WOLFF
064     */
065    public class BuilderConfiguration implements JavaAs3GroovyConfiguration {
066    
067            private final IProject project;
068        private final Map<Class<?>, Boolean> generatedClassCache = new HashMap<Class<?>, Boolean>();
069            private final Map<String, BuilderConfiguration> dependentProjectConfigurations = new HashMap<String, BuilderConfiguration>();
070        
071            private IJavaProject javaProject = null;
072        private GraniteProperties properties = null;
073        private As3TypeFactory as3TypeFactory = null;
074        private EntityFactory entityFactory = null;
075        private RemoteDestinationFactory remoteDestinationFactory = null;
076        private GroovyTemplateFactory groovyTemplateFactory = null;
077        private ClassLoader loader = null;
078        private List<PackageTranslator> translators = null;
079        private Listener listener = null;
080            
081            public BuilderConfiguration(Listener listener, IProject project) {
082                    this.listener = listener;
083                    this.project = project;
084            }
085    
086            public boolean isOutdated() {
087                    return GranitePropertiesLoader.isOutdated(project, getProperties());
088            }
089            
090            public IProject getProject() {
091                    return project;
092            }
093    
094            public IJavaProject getJavaProject() {
095                    if (javaProject == null) {
096                            javaProject = JavaCore.create(project);
097                    if (javaProject == null) {
098                            throw new RuntimeException(
099                                    new CoreException(ProjectUtil.createErrorStatus("Not a Java Project: " + project, null))
100                        );
101                    }
102                    }
103                    return javaProject;
104            }
105    
106            public GraniteProperties getProperties() {
107            if (properties == null) {
108                    try {
109                            properties = GranitePropertiesLoader.load(project);
110                    } catch (IOException e) {
111                            throw new RuntimeException(
112                            new CoreException(
113                                    ProjectUtil.createErrorStatus("Could not load Granite properties for: " + project,
114                                    e
115                            ))
116                        );
117                }
118            }
119            return properties;
120            }
121            
122            public As3TypeFactory getAs3TypeFactory() {
123                    if (as3TypeFactory == null) {
124                            String factoryClass = getProperties().getGas3().getAs3TypeFactory();
125                            if (factoryClass != null) {
126                                    try {
127                                            as3TypeFactory = BuilderUtil.newInstance(As3TypeFactory.class, factoryClass, getClassLoader());
128                                            as3TypeFactory.configure(
129                                                    getProperties().getGas3().isExternalizeLong(),
130                                                    getProperties().getGas3().isExternalizeBigInteger(),
131                                                    getProperties().getGas3().isExternalizeBigDecimal()
132                                            );
133                                    } catch (Exception e) {
134                                            throw new RuntimeException(
135                                    new CoreException(
136                                            ProjectUtil.createErrorStatus("Could not load As3TypeFactory class: " + factoryClass,
137                                            e
138                                    ))
139                                );
140                                    }
141                            }
142                            else
143                                    as3TypeFactory = new DefaultAs3TypeFactory();
144                    }
145                    return as3TypeFactory;
146            }
147            
148            public EntityFactory getEntityFactory() {
149                    if (entityFactory == null) {
150                            String factoryClass = getProperties().getGas3().getEntityFactory();
151                            if (factoryClass != null) {
152                                    try {
153                                            entityFactory = BuilderUtil.newInstance(EntityFactory.class, factoryClass, getClassLoader());
154                                    } catch (Exception e) {
155                                            throw new RuntimeException(
156                                    new CoreException(
157                                            ProjectUtil.createErrorStatus("Could not load EntityFactory class: " + factoryClass,
158                                            e
159                                    ))
160                                );
161                                    }
162                            }
163                            else
164                                    entityFactory = new DefaultEntityFactory();
165                    }
166                    return entityFactory;
167            }
168            
169            public RemoteDestinationFactory getRemoteDestinationFactory() {
170                    if (remoteDestinationFactory == null) {
171                            String factoryClass = getProperties().getGas3().getRemoteDestinationFactory();
172                            if (factoryClass != null) {
173                                    try {
174                                            remoteDestinationFactory = BuilderUtil.newInstance(RemoteDestinationFactory.class, factoryClass, getClassLoader());
175                                    } catch (Exception e) {
176                                            throw new RuntimeException(
177                                    new CoreException(
178                                            ProjectUtil.createErrorStatus("Could not load RemoteDestinationFactory class: " + factoryClass,
179                                            e
180                                    ))
181                                );
182                                    }
183                            }
184                    }
185                    return remoteDestinationFactory;
186            }
187    
188            public File getBaseOutputDir(JavaAs3Input input) {
189                    BuilderJavaAs3Input builderInput = (BuilderJavaAs3Input)input;
190                    return new File(ProjectUtil.getProjectFile(project), builderInput.getGas3Source().getBaseOutputDir(true));
191            }
192    
193            public File getOutputDir(JavaAs3Input input) {
194                    BuilderJavaAs3Input builderInput = (BuilderJavaAs3Input)input;
195                    return new File(ProjectUtil.getProjectFile(project), builderInput.getGas3Source().getOutputDir());
196            }
197    
198            public TemplateUri[] getTemplateUris(Kind kind, Class<?> clazz) {
199                    return getProperties().getGas3().getMatchingTemplateUris(kind);
200            }
201    
202            public List<PackageTranslator> getTranslators() {
203                    if (translators == null) {
204                            if (getProperties().getGas3().getTranslators().isEmpty())
205                                    translators = Collections.emptyList();
206                            else {
207                                    translators = new ArrayList<PackageTranslator>(getProperties().getGas3().getTranslators().size());
208                                    for (Gas3Translator translator : getProperties().getGas3().getTranslators())
209                                            translators.add(translator.getPackageTranslator());
210                            }
211                    }
212                    return translators;
213            }
214    
215            public String getUid() {
216                    return getProperties().getGas3().getUid();
217            }
218    
219            public boolean isGenerated(Class<?> clazz) {
220                    if (!getClassLoader().equals(clazz.getClassLoader()) || (clazz.isMemberClass() && !clazz.isEnum()))
221                            return false;
222                    
223                    Boolean generated = generatedClassCache.get(clazz);
224                    if (generated == null) {
225                            generated = Boolean.FALSE;
226                            
227                            JavaClassInfo info = ProjectUtil.getJavaClassInfo(getJavaProject(), clazz);
228                            if (info != null) {
229                                    Gas3Source source = getProperties().getGas3().getMatchingSource(
230                                    info.getSourceFolderPath(),
231                                    info.getSourceFilePath()
232                            );
233                                    generated = Boolean.valueOf(source != null);
234                            }
235                            else {
236                                    for (Gas3Project gas3Project : getProperties().getGas3().getProjects()) {
237                                            IProject dependentProject = ProjectUtil.getProject(getJavaProject().getProject(), gas3Project.getPath());
238                                            try {
239                                                    if (ProjectUtil.isGraniteProject(dependentProject)) {
240                                                            BuilderConfiguration configuration = dependentProjectConfigurations.get(dependentProject.getName());
241                                                            if (configuration == null) {
242                                                                    configuration = new BuilderConfiguration(listener, dependentProject);
243                                                                    dependentProjectConfigurations.put(dependentProject.getName(), configuration);
244                                                            }
245                                                            info = ProjectUtil.getJavaClassInfo(configuration.getJavaProject(), clazz);
246                                                            if (info != null) {
247                                                                    Gas3Source source = configuration.getProperties().getGas3().getMatchingSource(
248                                                                    info.getSourceFolderPath(),
249                                                                    info.getSourceFilePath()
250                                                            );
251                                                                    generated = Boolean.valueOf(source != null);
252                                                            }
253                                                    }
254                                            } catch (Exception e) {
255                                                    // ignore???
256                                            }
257                                    }
258                            }
259                            generatedClassCache.put(clazz, generated);
260                    }
261                    
262                    return generated.booleanValue();
263            }
264    
265            public GroovyTemplateFactory getGroovyTemplateFactory() {
266                    if (groovyTemplateFactory == null)
267                            groovyTemplateFactory = new GroovyTemplateFactory();
268                    return groovyTemplateFactory;
269            }
270    
271            public void resetClassLoader() {
272                    generatedClassCache.clear();
273                    dependentProjectConfigurations.clear();
274                    loader = null;
275            }
276            
277            public ClassLoader getClassLoader() {
278                    if (loader == null) {
279                            try {
280                                    List<URL> classpath = new ArrayList<URL>();
281                                    for (CpEntry entry : ProjectUtil.getFullClasspath(getJavaProject())) {
282                                            if (entry.getKind() == CpeKind.CONTAINER_JAR) {
283                                                    for (CpEntry cEntry : entry.getChildren())
284                                                            classpath.add(cEntry.toURL());
285                                            }
286                                            else
287                                                    classpath.add(entry.toURL());
288                                    }
289                                    
290                                    for (Gas3Classpath gas3Classpath : getProperties().getGas3().getClasspaths()) {
291                                            File file = new File(gas3Classpath.getPath());
292                                            if (file.exists()) {
293                                                    try {
294                                                            classpath.add(file.toURI().toURL());
295                                                    } catch (MalformedURLException e) {
296                                                            // Should never happen...
297                                                    }
298                                            }
299                                    }
300                                    
301                                    for (Gas3Project gas3Project : getProperties().getGas3().getProjects()) {
302                                            IProject dependentProject = ProjectUtil.getProject(getJavaProject().getProject(), gas3Project.getPath());
303                                            if (ProjectUtil.isGraniteProject(dependentProject)) {
304                                                    for (CpEntry entry : ProjectUtil.getFullClasspath(JavaCore.create(dependentProject))) {
305                                                            if (entry.getKind() == CpeKind.CONTAINER_JAR) {
306                                                                    for (CpEntry cEntry : entry.getChildren())
307                                                                            classpath.add(cEntry.toURL());
308                                                            }
309                                                            else
310                                                                    classpath.add(entry.toURL());
311                                                    }
312                                            }
313                                    }
314                                    
315                                    if (getProperties().getGas3().isDebugEnabled()) {
316                                            listener.debug("Using classpath: {");
317                                            for (URL url : classpath)
318                                                    listener.debug("  " + (url != null ? url.toString() : "<null>"));
319                                            listener.debug("}");
320                                    }
321                                    
322                                    loader = URLClassLoader.newInstance(
323                                            classpath.toArray(new URL[classpath.size()]),
324                                            new BuilderParentClassLoader()
325                                    );
326                            } catch (Exception e) {
327                                    throw new RuntimeException(e);
328                            }
329                    }
330                    return loader;
331            }
332    }