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 021package org.granite.builder; 022 023import java.io.File; 024import java.io.IOException; 025import java.net.MalformedURLException; 026import java.net.URL; 027import java.net.URLClassLoader; 028import java.util.ArrayList; 029import java.util.Collections; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Map; 033 034import org.eclipse.core.resources.IProject; 035import org.eclipse.core.runtime.CoreException; 036import org.eclipse.jdt.core.IJavaProject; 037import org.eclipse.jdt.core.JavaCore; 038import org.granite.builder.properties.Gas3Classpath; 039import org.granite.builder.properties.Gas3Project; 040import org.granite.builder.properties.Gas3Source; 041import org.granite.builder.properties.Gas3Translator; 042import org.granite.builder.properties.GraniteProperties; 043import org.granite.builder.properties.GranitePropertiesLoader; 044import org.granite.builder.util.BuilderUtil; 045import org.granite.builder.util.JavaClassInfo; 046import org.granite.builder.util.ProjectUtil; 047import org.granite.builder.util.ProjectUtil.CpEntry; 048import org.granite.builder.util.ProjectUtil.CpEntry.CpeKind; 049import org.granite.generator.Listener; 050import org.granite.generator.TemplateUri; 051import org.granite.generator.as3.As3TypeFactory; 052import org.granite.generator.as3.DefaultAs3TypeFactory; 053import org.granite.generator.as3.DefaultEntityFactory; 054import org.granite.generator.as3.EntityFactory; 055import org.granite.generator.as3.JavaAs3GroovyConfiguration; 056import org.granite.generator.as3.JavaAs3Input; 057import org.granite.generator.as3.PackageTranslator; 058import org.granite.generator.as3.RemoteDestinationFactory; 059import org.granite.generator.as3.reflect.JavaType.Kind; 060import org.granite.generator.gsp.GroovyTemplateFactory; 061 062/** 063 * @author Franck WOLFF 064 */ 065public 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}