001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
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 clientTypeFactory = 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 @Override
123 public As3TypeFactory getAs3TypeFactory() {
124 if (clientTypeFactory == null) {
125 String factoryClass = getProperties().getGas3().getAs3TypeFactory();
126 if (factoryClass != null) {
127 try {
128 clientTypeFactory = BuilderUtil.newInstance(As3TypeFactory.class, factoryClass, getClassLoader());
129 clientTypeFactory.configure(
130 getProperties().getGas3().isExternalizeLong(),
131 getProperties().getGas3().isExternalizeBigInteger(),
132 getProperties().getGas3().isExternalizeBigDecimal()
133 );
134 } catch (Exception e) {
135 throw new RuntimeException(
136 new CoreException(
137 ProjectUtil.createErrorStatus("Could not load As3TypeFactory class: " + factoryClass,
138 e
139 ))
140 );
141 }
142 }
143 else
144 clientTypeFactory = new DefaultAs3TypeFactory();
145 }
146 return clientTypeFactory;
147 }
148
149 @Override
150 public EntityFactory getEntityFactory() {
151 if (entityFactory == null) {
152 String factoryClass = getProperties().getGas3().getEntityFactory();
153 if (factoryClass != null) {
154 try {
155 entityFactory = BuilderUtil.newInstance(EntityFactory.class, factoryClass, getClassLoader());
156 } catch (Exception e) {
157 throw new RuntimeException(
158 new CoreException(
159 ProjectUtil.createErrorStatus("Could not load EntityFactory class: " + factoryClass,
160 e
161 ))
162 );
163 }
164 }
165 else
166 entityFactory = new DefaultEntityFactory();
167 }
168 return entityFactory;
169 }
170
171 @Override
172 public RemoteDestinationFactory getRemoteDestinationFactory() {
173 if (remoteDestinationFactory == null) {
174 String factoryClass = getProperties().getGas3().getRemoteDestinationFactory();
175 if (factoryClass != null) {
176 try {
177 remoteDestinationFactory = BuilderUtil.newInstance(RemoteDestinationFactory.class, factoryClass, getClassLoader());
178 } catch (Exception e) {
179 throw new RuntimeException(
180 new CoreException(
181 ProjectUtil.createErrorStatus("Could not load RemoteDestinationFactory class: " + factoryClass,
182 e
183 ))
184 );
185 }
186 }
187 }
188 return remoteDestinationFactory;
189 }
190
191 @Override
192 public File getBaseOutputDir(JavaAs3Input input) {
193 BuilderJavaClientInput builderInput = (BuilderJavaClientInput)input;
194 return new File(ProjectUtil.getProjectFile(project), builderInput.getGas3Source().getBaseOutputDir(true));
195 }
196
197 @Override
198 public File getOutputDir(JavaAs3Input input) {
199 BuilderJavaClientInput builderInput = (BuilderJavaClientInput)input;
200 return new File(ProjectUtil.getProjectFile(project), builderInput.getGas3Source().getOutputDir());
201 }
202
203 @Override
204 public TemplateUri[] getTemplateUris(Kind kind, Class<?> clazz) {
205 return getProperties().getGas3().getMatchingTemplateUris(kind);
206 }
207
208 @Override
209 public List<PackageTranslator> getTranslators() {
210 if (translators == null) {
211 if (getProperties().getGas3().getTranslators().isEmpty())
212 translators = Collections.emptyList();
213 else {
214 translators = new ArrayList<PackageTranslator>(getProperties().getGas3().getTranslators().size());
215 for (Gas3Translator translator : getProperties().getGas3().getTranslators())
216 translators.add(translator.getPackageTranslator());
217 }
218 }
219 return translators;
220 }
221
222 public PackageTranslator getPackageTranslator(String packageName) {
223 PackageTranslator translator = null;
224
225 int weight = 0;
226 for (PackageTranslator t : getTranslators()) {
227 int w = t.match(packageName);
228 if (w > weight) {
229 weight = w;
230 translator = t;
231 }
232 }
233
234 return translator;
235 }
236
237 @Override
238 public String getUid() {
239 return getProperties().getGas3().getUid();
240 }
241
242 @Override
243 public boolean isGenerated(Class<?> clazz) {
244 if (!getClassLoader().equals(clazz.getClassLoader()) || (clazz.isMemberClass() && !clazz.isEnum()))
245 return false;
246
247 Boolean generated = generatedClassCache.get(clazz);
248 if (generated == null) {
249 generated = Boolean.FALSE;
250
251 JavaClassInfo info = ProjectUtil.getJavaClassInfo(getJavaProject(), clazz);
252 if (info != null) {
253 Gas3Source source = getProperties().getGas3().getMatchingSource(
254 info.getSourceFolderPath(),
255 info.getSourceFilePath()
256 );
257 generated = Boolean.valueOf(source != null);
258 }
259 else {
260 for (Gas3Project gas3Project : getProperties().getGas3().getProjects()) {
261 IProject dependentProject = ProjectUtil.getProject(getJavaProject().getProject(), gas3Project.getPath());
262 try {
263 if (ProjectUtil.isGraniteProject(dependentProject)) {
264 BuilderConfiguration configuration = dependentProjectConfigurations.get(dependentProject.getName());
265 if (configuration == null) {
266 configuration = new BuilderConfiguration(listener, dependentProject);
267 dependentProjectConfigurations.put(dependentProject.getName(), configuration);
268 }
269 info = ProjectUtil.getJavaClassInfo(configuration.getJavaProject(), clazz);
270 if (info != null) {
271 Gas3Source source = configuration.getProperties().getGas3().getMatchingSource(
272 info.getSourceFolderPath(),
273 info.getSourceFilePath()
274 );
275 generated = Boolean.valueOf(source != null);
276 }
277 }
278 } catch (Exception e) {
279 // ignore???
280 }
281 }
282 }
283 generatedClassCache.put(clazz, generated);
284 }
285
286 return generated.booleanValue();
287 }
288
289 @Override
290 public GroovyTemplateFactory getGroovyTemplateFactory() {
291 if (groovyTemplateFactory == null)
292 groovyTemplateFactory = new GroovyTemplateFactory();
293 return groovyTemplateFactory;
294 }
295
296 public void resetClassLoader() {
297 generatedClassCache.clear();
298 dependentProjectConfigurations.clear();
299 loader = null;
300 }
301
302 @Override
303 public ClassLoader getClassLoader() {
304 if (loader == null) {
305 try {
306 List<URL> classpath = new ArrayList<URL>();
307 for (CpEntry entry : ProjectUtil.getFullResolvedClasspath(getJavaProject())) {
308 if (entry.getKind() == CpeKind.CONTAINER_JAR) {
309 for (CpEntry cEntry : entry.getChildren())
310 addToClasspath(classpath, cEntry.toURL());
311 }
312 else
313 addToClasspath(classpath, entry.toURL());
314 }
315
316 for (Gas3Classpath gas3Classpath : getProperties().getGas3().getClasspaths()) {
317 File file = new File(gas3Classpath.getPath());
318 if (file.exists()) {
319 try {
320 addToClasspath(classpath, file.toURI().toURL());
321 } catch (MalformedURLException e) {
322 // Should never happen...
323 }
324 }
325 }
326
327 for (Gas3Project gas3Project : getProperties().getGas3().getProjects()) {
328 IProject dependentProject = ProjectUtil.getProject(getJavaProject().getProject(), gas3Project.getPath());
329 if (ProjectUtil.isGraniteProject(dependentProject)) {
330 for (CpEntry entry : ProjectUtil.getFullResolvedClasspath(JavaCore.create(dependentProject))) {
331 if (entry.getKind() == CpeKind.CONTAINER_JAR) {
332 for (CpEntry cEntry : entry.getChildren())
333 addToClasspath(classpath, cEntry.toURL());
334 }
335 else
336 addToClasspath(classpath, entry.toURL());
337 }
338 }
339 }
340
341 if (getProperties().getGas3().isDebugEnabled()) {
342 listener.debug("Using classpath: {");
343 for (URL url : classpath)
344 listener.debug(" " + (url != null ? url.toString() : "<null>"));
345 listener.debug("}");
346 }
347
348 loader = URLClassLoader.newInstance(
349 classpath.toArray(new URL[classpath.size()]),
350 new BuilderParentClassLoader()
351 );
352 } catch (Exception e) {
353 throw new RuntimeException(e);
354 }
355 }
356 return loader;
357 }
358
359 private void addToClasspath(List<URL> classpath, URL url) {
360 if (!classpath.contains(url))
361 classpath.add(url);
362 }
363
364 @Override
365 public File getWorkingDirectory() {
366 return ProjectUtil.getProjectFile(project);
367 }
368 }