blob: aac738a70172704a50e200c21d5f8b070dce1a27 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.j2ee.persistence.action;
import org.netbeans.api.java.source.TreeUtilities;
import org.netbeans.modules.j2ee.persistence.spi.entitymanagergenerator.EntityManagerGenerationStrategyResolver;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import java.io.IOException;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.Task;
import org.netbeans.api.java.source.TreeMaker;
import org.netbeans.api.java.source.WorkingCopy;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.j2ee.persistence.spi.entitymanagergenerator.ApplicationManagedResourceTransactionInJ2SE;
import org.netbeans.modules.j2ee.persistence.spi.entitymanagergenerator.EntityManagerGenerationStrategy;
import org.netbeans.modules.j2ee.persistence.api.PersistenceScope;
import org.netbeans.modules.j2ee.persistence.dd.PersistenceMetadata;
import org.netbeans.modules.j2ee.persistence.dd.common.Persistence;
import org.netbeans.modules.j2ee.persistence.dd.common.PersistenceUnit;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileObject;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
/**
* Generates appropriate code for retrieving and invoking <code>javax.persistence.EntityManager</code>.
* The generated code depends on the target class' enviroment.
*
* TODO: move this class to different package if anybody else wants to use it
* @author Martin Adamek, Erno Mononen
*/
public final class EntityManagerGenerator {
/**
* The fully qualified name of the target class.
*/
private final String fqn;
/**
* The target java source file.
*/
private final JavaSource targetSource;
/**
* The file object of the target source file.
*/
private final FileObject targetFo;
/**
* The project to which the target file belongs.
*/
private final Project project;
/**
* Creates a new EntityManagerGenerator.
* @param targetFo the file object of the target java source file.
* @param fqn the fully qualified name of the target java class.
*/
public EntityManagerGenerator(FileObject targetFo, String fqn) {
this.fqn = fqn;
this.targetFo = targetFo;
this.targetSource = JavaSource.forFileObject(targetFo);
this.project = FileOwnerQuery.getOwner(targetFo);
}
/**
* Generates the code needed for retrieving and invoking
* an instance of <code>javax.persistence.EntityManager</code>. The generated
* code depends on the environment of the target class (e.g. whether
* it supports injection or not).
*
* @param options the options for the generation. Must not be null.
* @return the modified file object of the target java class.
*/
public FileObject generate(final GenerationOptions options) throws IOException{
final Class<? extends EntityManagerGenerationStrategy> strategyClass = getStrategy();
if (strategyClass == null){
NotifyDescriptor d = new NotifyDescriptor.Message(
NbBundle.getMessage(EntityManagerGenerator.class, "ERR_NotSupported"), NotifyDescriptor.INFORMATION_MESSAGE);
DialogDisplayer.getDefault().notify(d);
return targetFo;
}
return generate(options, strategyClass);
}
/**
* Generates the code needed for retrieving and invoking
* an instance of <code>javax.persistence.EntityManager</code>. The generated
* code depends on the given <code>strategyClass</code>.
*
* @param options the options for the generation. Must not be null.
* @param strategyClass the generation strategy that should be used. Must not be null.
* @return the modified file object of the target java class.
*/
public FileObject generate(final GenerationOptions options,
final Class<? extends EntityManagerGenerationStrategy> strategyClass) throws IOException{
Parameters.notNull("options", options); //NOI18N
Parameters.notNull("strategyClass", strategyClass); //NOI18N
Task task = new Task<WorkingCopy>() {
public void run(WorkingCopy workingCopy) throws Exception {
workingCopy.toPhase(Phase.RESOLVED);
CompilationUnitTree cut = workingCopy.getCompilationUnit();
TreeMaker make = workingCopy.getTreeMaker();
for (Tree typeDeclaration : cut.getTypeDecls()){
if (TreeUtilities.CLASS_TREE_KINDS.contains(typeDeclaration.getKind())){
ClassTree clazz = (ClassTree) typeDeclaration;
EntityManagerGenerationStrategy strategy = instantiateStrategy(strategyClass, workingCopy, make, clazz, options);
workingCopy.rewrite(clazz, strategy.generate());
}
}
}
};
targetSource.runModificationTask(task).commit();
return targetFo;
}
private Class<? extends EntityManagerGenerationStrategy> getStrategy(){
EntityManagerGenerationStrategyResolver resolver = project.getLookup().lookup(EntityManagerGenerationStrategyResolver.class);
if (resolver != null){
return resolver.resolveStrategy(targetFo);
}
// must be a java se project (we don't want it to implement the EntityManagerGenerationStrategyResolver SPI)
return ApplicationManagedResourceTransactionInJ2SE.class;
}
private EntityManagerGenerationStrategy instantiateStrategy(Class<? extends EntityManagerGenerationStrategy> strategy, WorkingCopy workingCopy,
TreeMaker make, ClassTree clazz, GenerationOptions options){
EntityManagerGenerationStrategy result = null;
try{
result = strategy.newInstance();
result.setClassTree(clazz);
result.setWorkingCopy(workingCopy);
result.setGenerationOptions(options);
result.setTreeMaker(make);
result.setPersistenceUnit(getPersistenceUnit());
} catch (IllegalAccessException iae){
throw new RuntimeException(iae); //TODO
} catch (InstantiationException ie){
throw new RuntimeException(ie); //TODO
}
return result;
}
private PersistenceUnit getPersistenceUnit() {
PersistenceScope persistenceScope = PersistenceScope.getPersistenceScope(targetFo);
if (persistenceScope == null){
return null;
}
try {
Persistence persistence = PersistenceMetadata.getDefault().getRoot(persistenceScope.getPersistenceXml());
if(persistence != null){
PersistenceUnit[] pus=persistence.getPersistenceUnit();
PersistenceUnit ret=pus.length>0 ? pus[0] : null;//if there is only one pu, return in any case (even if do not contain fqn)
if(pus.length>1) {//searchh for best match
PersistenceUnit forAll=null;
PersistenceUnit forOne=null;
for(int i=0;i<pus.length && forOne==null;i++) {
PersistenceUnit tmp=pus[i];
if(forAll ==null && !tmp.isExcludeUnlistedClasses()) forAll=tmp;//first match sutable for all entities in the project
if(tmp.isExcludeUnlistedClasses()) {
String []classes = tmp.getClass2();
for(String clas:classes){
if(fqn.equals(clas)) {
forOne = tmp;
break;
}
}
}
}
ret = forOne != null ? forOne : (forAll != null ? forAll : ret);
}
return ret;
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
return null;
}
}