blob: 265a28a516ccc44273a3b174b2b833b95c0216d2 [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.maven.jaxws.wizards;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.VariableTree;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.swing.SwingUtilities;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.Comment;
import org.netbeans.api.java.source.GeneratorUtilities;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.ui.ScanDialog;
import org.netbeans.api.java.source.ModificationResult;
import org.netbeans.api.java.source.TreeMaker;
import org.netbeans.api.java.source.WorkingCopy;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.modules.j2ee.api.ejbjar.EjbReference;
import org.netbeans.modules.j2ee.core.api.support.classpath.ContainerClassPathModifier;
import org.netbeans.modules.maven.jaxws.MavenJAXWSSupportImpl;
import org.netbeans.modules.maven.jaxws.MavenWebService;
import org.netbeans.modules.maven.jaxws.WSUtils;
import org.netbeans.modules.maven.model.ModelOperation;
import org.netbeans.modules.maven.model.Utilities;
import org.netbeans.modules.maven.model.pom.POMModel;
import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlModeler;
import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlOperation;
import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlParameter;
import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlPort;
import org.netbeans.modules.websvc.api.jaxws.wsdlmodel.WsdlService;
import org.netbeans.modules.websvc.api.support.ServiceCreator;
import java.io.IOException;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.maven.api.execute.RunConfig;
import org.netbeans.modules.maven.api.execute.RunUtils;
import org.netbeans.modules.maven.jaxws.MavenModelUtils;
import org.netbeans.modules.websvc.api.support.java.GenerationUtils;
import org.netbeans.modules.websvc.api.support.java.SourceUtils;
import org.netbeans.modules.websvc.jaxws.light.api.JAXWSLightSupport;
import org.netbeans.spi.project.ui.templates.support.Templates;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
import org.openide.NotifyDescriptor;
import org.openide.WizardDescriptor;
import org.openide.cookies.OpenCookie;
import org.openide.cookies.SaveCookie;
import org.openide.execution.ExecutorTask;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
/**
*
* @author Radko, Milan Kuchtiak
*/
public class JaxWsServiceCreator implements ServiceCreator {
private static final String SOAP_BINDING_TYPE = "javax.xml.ws.soap.SOAPBinding"; //NOI18N
private static final String BINDING_TYPE_ANNOTATION = "javax.xml.ws.BindingType"; //NOI18N
private static final String SOAP12_HTTP_BINDING = "SOAP12HTTP_BINDING"; //NOI18N
private Project project;
private WizardDescriptor wiz;
private boolean addJaxWsLib;
private int serviceType;
private static final Logger LOG = Logger.getLogger( JaxWsServiceCreator.class.getCanonicalName());
/**
* Creates a new instance of WebServiceClientCreator
*/
public JaxWsServiceCreator(Project project, WizardDescriptor wiz, boolean addJaxWsLib) {
this.project = project;
this.wiz = wiz;
this.addJaxWsLib = addJaxWsLib;
}
@Override
public void createService() throws IOException {
serviceType = ((Integer) wiz.getProperty(WizardProperties.WEB_SERVICE_TYPE)).intValue();
// Use Progress API to display generator messages.
final ProgressHandle handle = ProgressHandleFactory.createHandle(NbBundle.getMessage(JaxWsServiceCreator.class, "TXT_WebServiceGeneration")); //NOI18N
handle.start(100);
Runnable r = new Runnable() {
@Override
public void run() {
try {
generateWebService(handle);
} catch (IOException e) {
//finish progress bar
handle.finish();
String message = e.getLocalizedMessage();
if (message != null) {
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
NotifyDescriptor nd = new NotifyDescriptor.Message(message, NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(nd);
} else {
ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, e);
}
}
}
};
RequestProcessor.getDefault().post(r);
}
@Override
public void createServiceFromWsdl() throws IOException {
//initProjectInfo(project);
final ProgressHandle handle = ProgressHandleFactory.createHandle(NbBundle.getMessage(JaxWsServiceCreator.class, "TXT_WebServiceGeneration")); //NOI18N
Runnable r = new Runnable() {
@Override
public void run() {
try {
handle.start(100);
generateWsFromWsdl15(handle);
} catch (IOException e) {
//finish progress bar
handle.finish();
String message = e.getLocalizedMessage();
if (message != null) {
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
NotifyDescriptor nd = new NotifyDescriptor.Message(message, NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(nd);
} else {
ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, e);
}
}
}
};
RequestProcessor.getDefault().post(r);
}
//TODO it should be refactored to prevent duplicate code but it is more readable now during development
private void generateWebService(ProgressHandle handle) throws IOException {
FileObject pkg = Templates.getTargetFolder(wiz);
if (serviceType == WizardProperties.FROM_SCRATCH) {
handle.progress(NbBundle.getMessage(JaxWsServiceCreator.class, "MSG_GEN_WS"), 50); //NOI18N
//add the JAXWS 2.0 library, if not already added
if (addJaxWsLib) {
MavenModelUtils.addMetroLibrary(project);
}
generateJaxWSImplFromTemplate(pkg, WSUtils.isEJB(project), false, false);
handle.finish();
} else if (serviceType == WizardProperties.ENCAPSULATE_SESSION_BEAN) {
String wsName = Templates.getTargetName(wiz);
handle.progress(NbBundle.getMessage(JaxWsServiceCreator.class, "MSG_GEN_SEI_AND_IMPL"), 50); //NOI18N
Node[] nodes = (Node[]) wiz.getProperty(WizardProperties.DELEGATE_TO_SESSION_BEAN);
generateWebServiceFromEJB(wsName, pkg, nodes);
handle.finish();
}
}
private void generateWsFromWsdl15(final ProgressHandle handle) throws IOException {
handle.progress(NbBundle.getMessage(JaxWsServiceCreator.class, "MSG_GEN_WS"), 50); //NOI18N
JAXWSLightSupport jaxWsSupport = JAXWSLightSupport.getJAXWSLightSupport(project.getProjectDirectory());
String wsdlUrl = (String)wiz.getProperty(WizardProperties.WSDL_URL);
String filePath = (String)wiz.getProperty(WizardProperties.WSDL_FILE_PATH);
//Boolean useDispatch = (Boolean) wiz.getProperty(ClientWizardProperties.USEDISPATCH);
//if (wsdlUrl==null) wsdlUrl = "file:"+(filePath.startsWith("/")?filePath:"/"+filePath); //NOI18N
if(wsdlUrl == null) {
wsdlUrl = FileUtil.toFileObject(FileUtil.normalizeFile(new File(filePath))).getURL().toExternalForm();
}
FileObject localWsdlFolder = jaxWsSupport.getWsdlFolder(true);
boolean hasSrcFolder = false;
File srcFile = new File (FileUtil.toFile(project.getProjectDirectory()),"src"); //NOI18N
if (srcFile.exists()) {
hasSrcFolder = true;
} else {
hasSrcFolder = srcFile.mkdirs();
}
if (localWsdlFolder != null) {
FileObject wsdlFo = null;
try {
wsdlFo = WSUtils.retrieveResource(
localWsdlFolder,
(hasSrcFolder ? new URI(MavenJAXWSSupportImpl.CATALOG_PATH) : new URI("jax-ws-catalog.xml")), //NOI18N
new URI(wsdlUrl));
} catch (URISyntaxException ex) {
//ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
String mes = NbBundle.getMessage(JaxWsServiceCreator.class, "ERR_IncorrectURI", wsdlUrl); // NOI18N
NotifyDescriptor desc = new NotifyDescriptor.Message(mes, NotifyDescriptor.Message.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(desc);
} catch (UnknownHostException ex) {
//ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
String mes = NbBundle.getMessage(JaxWsServiceCreator.class, "ERR_UnknownHost", ex.getMessage()); // NOI18N
NotifyDescriptor desc = new NotifyDescriptor.Message(mes, NotifyDescriptor.Message.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(desc);
} catch (IOException ex) {
//ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
String mes = NbBundle.getMessage(JaxWsServiceCreator.class, "ERR_WsdlRetrieverFailure", wsdlUrl); // NOI18N
NotifyDescriptor desc = new NotifyDescriptor.Message(mes, NotifyDescriptor.Message.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(desc);
}
if (wsdlFo != null) {
final WsdlService wsdlService = (WsdlService) wiz.getProperty(WizardProperties.WSDL_SERVICE);
final WsdlPort wsdlPort = (WsdlPort) wiz.getProperty(WizardProperties.WSDL_PORT);
if (wsdlService == null || wsdlPort == null) {
WsdlModeler wsdlModeler = (WsdlModeler) wiz.getProperty(WizardProperties.WSDL_MODELER);
if (wsdlModeler != null && wsdlModeler.getCreationException() != null) {
handle.finish();
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
NbBundle.getMessage(JaxWsServiceCreator.class, "TXT_CannotGenerateArtifacts",
wsdlModeler.getCreationException().getLocalizedMessage()),
NotifyDescriptor.ERROR_MESSAGE));
} else {
handle.finish();
}
} else {
final boolean isJaxWsLibrary = MavenModelUtils.hasJaxWsAPI(project);
final String relativePath = FileUtil.getRelativePath(localWsdlFolder, wsdlFo);
final String serviceName = wsdlFo.getName();
Preferences prefs = ProjectUtils.getPreferences(project, MavenWebService.class,true);
if (prefs != null) {
// remember original WSDL URL for service
prefs.put(MavenWebService.SERVICE_PREFIX+WSUtils.getUniqueId(wsdlFo.getName(), jaxWsSupport.getServices()), wsdlUrl);
}
if (!isJaxWsLibrary) {
try {
MavenModelUtils.addMetroLibrary(project);
MavenModelUtils.addJavadoc(project);
} catch (Exception ex) {
Logger.getLogger(
JaxWsServiceCreator.class.getName()).log(
Level.INFO, "Cannot add Metro libbrary to pom file", ex); //NOI18N
}
}
ModelOperation<POMModel> operation = new ModelOperation<POMModel>() {
@Override
public void performOperation(POMModel model) {
org.netbeans.modules.maven.model.pom.Plugin plugin =
WSUtils.isEJB(project) ?
MavenModelUtils.addJaxWSPlugin(model, "2.0") : //NOI18N
MavenModelUtils.addJaxWSPlugin(model);
MavenModelUtils.addWsimportExecution(plugin,
serviceName, relativePath,null );
if (WSUtils.isWeb(project)) { // expecting web project
MavenModelUtils.addWarPlugin(model, false);
} else { // J2SE Project
MavenModelUtils.addWsdlResources(model);
}
}
};
Utilities.performPOMModelOperations(project.getProjectDirectory().getFileObject("pom.xml"),
Collections.singletonList(operation));
// create empty web service implementation class
FileObject pkg = Templates.getTargetFolder(wiz);
boolean useProvider = (Boolean)wiz.getProperty(WizardProperties.USE_PROVIDER);
boolean isStateless = (Boolean)wiz.getProperty(WizardProperties.IS_STATELESS_BEAN);
final FileObject targetFile = generateJaxWSImplFromTemplate(pkg, isStateless, true, useProvider);
// execute wsimport goal
RunConfig cfg = RunUtils.createRunConfig(
FileUtil.toFile(project.getProjectDirectory()),
project,
"JAX-WS:wsimport", //NOI18N
Collections.singletonList("compile")); //NOI18N
ExecutorTask task = RunUtils.executeMaven(cfg);
try {
task.waitFinished(60000);
} catch (InterruptedException ex) {
}
try {
String wsdlLocationPrefix = WSUtils.isWeb(project) ? "WEB-INF/wsdl/" : "META-INF/wsdl/"; //NOI18N
generateJaxWsImplClass(targetFile, wsdlService, wsdlPort, wsdlLocationPrefix+relativePath, useProvider); //NOI18N
DataObject targetDo = DataObject.find(targetFile);
if (targetDo != null) {
SaveCookie save = targetDo.getCookie(SaveCookie.class);
if (save != null) {
save.save();
}
}
} catch (IOException ex) {
ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, ex);
}
}
}
}
handle.finish();
}
private FileObject generateJaxWSImplFromTemplate(FileObject pkg, boolean isEjbTemplate, boolean fromWsdl, boolean useProvider) throws IOException {
DataFolder df = DataFolder.findFolder(pkg);
FileObject template = Templates.getTemplate(wiz);
if (useProvider) {
FileObject templateParent = template.getParent();
if (isEjbTemplate) {
template = templateParent.getFileObject("EjbWebServiceProvider", "java"); //NOI18N
} else {
template = templateParent.getFileObject("WebServiceProvider", "java"); //NOI18N
}
} else if (!fromWsdl && (Boolean)wiz.getProperty(WizardProperties.IS_STATELESS_BEAN)) {
FileObject templateParent = template.getParent();
template = templateParent.getFileObject("EjbWebService", "java"); //NOI18N
}
DataObject dTemplate = DataObject.find(template);
DataObject dobj = dTemplate.createFromTemplate(df, Templates.getTargetName(wiz));
FileObject createdFile = dobj.getPrimaryFile();
/*createdFile.setAttribute("jax-ws-service", java.lang.Boolean.TRUE); // NOI18N
try {
dobj.setValid(false);
}
catch( PropertyVetoException e ){
LOG.log(Level.WARNING, null , e);
}*/
dobj = DataObject.find(createdFile);
openFileInEditor(dobj);
return createdFile;
}
private ClassPath getClassPathForFile(Project project, FileObject file) {
SourceGroup[] srcGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
for (SourceGroup srcGroup: srcGroups) {
FileObject srcRoot = srcGroup.getRootFolder();
if (FileUtil.isParentOf(srcRoot, file)) {
return ClassPath.getClassPath(srcRoot, ClassPath.SOURCE);
}
}
return null;
}
public static void openFileInEditor(DataObject dobj) {
final OpenCookie openCookie = dobj.getCookie(OpenCookie.class);
if (openCookie != null) {
RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
openCookie.open();
}
}, 1000);
}
}
private void generateJaxWsImplClass(FileObject targetFile, final WsdlService service, final WsdlPort port, final String wsdlLocation, final boolean useProvider) throws IOException {
final JavaSource targetSource = JavaSource.forFileObject(targetFile);
final boolean[] isIncomplete = new boolean[1];
final CancellableTask<WorkingCopy> task = new CancellableTask<WorkingCopy>() {
@Override
public void run(WorkingCopy workingCopy) throws java.io.IOException {
workingCopy.toPhase(Phase.RESOLVED);
ClassTree javaClass = SourceUtils.getPublicTopLevelTree(workingCopy);
if (javaClass != null) {
TreeMaker make = workingCopy.getTreeMaker();
GenerationUtils genUtils = GenerationUtils.newInstance(workingCopy);
//add @WebService annotation
List<ExpressionTree> attrs = new ArrayList<ExpressionTree>();
attrs.add(
make.Assignment(make.Identifier("serviceName"),
make.Literal(service.getName()))); //NOI18N
attrs.add(
make.Assignment(make.Identifier("portName"),
make.Literal(port.getName()))); //NOI18N
if (!useProvider) {
attrs.add(
make.Assignment(make.Identifier("endpointInterface"),
make.Literal(port.getJavaName()))); //NOI18N
}
attrs.add(
make.Assignment(make.Identifier("targetNamespace"),
make.Literal(port.getNamespaceURI()))); //NOI18N
attrs.add(
make.Assignment(make.Identifier("wsdlLocation"),
make.Literal(wsdlLocation))); //NOI18N
AnnotationTree WSAnnotation = make.Annotation(
useProvider ?
make.QualIdent("javax.xml.ws.WebServiceProvider") : make.QualIdent("javax.jws.WebService"), //NOI18N
attrs);
ClassTree modifiedClass = genUtils.addAnnotation(javaClass,
WSAnnotation);
if (WsdlPort.SOAP_VERSION_12.equals(port.getSOAPVersion())) {
//if SOAP 1.2 binding, add BindingType annotation
TypeElement bindingElement = workingCopy.getElements().
getTypeElement(BINDING_TYPE_ANNOTATION);
if (bindingElement == null) {
isIncomplete[0] = true;
}
else {
TypeElement soapBindingElement = workingCopy.
getElements().getTypeElement(SOAP_BINDING_TYPE);
ExpressionTree exp = make.MemberSelect(
make.QualIdent(soapBindingElement), SOAP12_HTTP_BINDING);
AnnotationTree bindingAnnotation = make.Annotation(
make.QualIdent(bindingElement),
Collections.<ExpressionTree>singletonList(exp));
modifiedClass = genUtils.addAnnotation(modifiedClass,
bindingAnnotation);
}
}
if (!useProvider) {
// add @Stateless annotation
if (WSUtils.isEJB(project)) {
TypeElement statelessAn = workingCopy.getElements().
getTypeElement("javax.ejb.Stateless"); //NOI18N
if (statelessAn != null) {
AnnotationTree StatelessAnnotation = make.Annotation(
make.QualIdent(statelessAn),
Collections.<ExpressionTree>emptyList());
modifiedClass = genUtils.addAnnotation(modifiedClass,
StatelessAnnotation);
}
else {
isIncomplete[0] = true;
}
}
List<WsdlOperation> operations = port.getOperations();
for (WsdlOperation operation : operations) {
// return type
String returnType = operation.getReturnTypeName();
// create parameters
List<WsdlParameter> parameters = operation.getParameters();
List<VariableTree> params = new ArrayList<VariableTree>();
for (WsdlParameter parameter : parameters) {
// create parameter:
// final ObjectOutput arg0
params.add(make.Variable(
make.Modifiers(
Collections.<Modifier>emptySet(),
Collections.<AnnotationTree>emptyList()),
parameter.getName(), // name
make.Identifier(parameter.getTypeName()), // parameter type
null // initializer - does not make sense in parameters.
));
}
// create exceptions
Iterator<String> exceptions = operation.getExceptions();
List<ExpressionTree> exc = new ArrayList<ExpressionTree>();
while (exceptions.hasNext()) {
String exception = exceptions.next();
TypeElement excEl = workingCopy.getElements().getTypeElement(exception);
if (excEl != null) {
exc.add(make.QualIdent(excEl));
} else {
isIncomplete[0] = true;
exc.add(make.Identifier(exception));
}
}
// create method
ModifiersTree methodModifiers = make.Modifiers(
Collections.<Modifier>singleton(Modifier.PUBLIC),
Collections.<AnnotationTree>emptyList());
MethodTree method = make.Method(
methodModifiers, // public
operation.getJavaName(), // operation name
make.Identifier(returnType), // return type
Collections.<TypeParameterTree>emptyList(), // type parameters - none
params,
exc, // throws
"{ //TODO implement this method\nthrow new UnsupportedOperationException(\"Not implemented yet.\") }", // body text
null // default value - not applicable here, used by annotations
);
modifiedClass = make.addClassMember(modifiedClass, method);
}
}
workingCopy.rewrite(javaClass, modifiedClass);
}
}
@Override
public void cancel() {
}
};
ModificationResult modificationTask = targetSource.runModificationTask(task);
if ( isIncomplete[0] &&
org.netbeans.api.java.source.SourceUtils.isScanInProgress())
{
final String title = NbBundle.getMessage(JaxWsServiceCreator.class,
"LBL_GenWsClass"); // NOI18N
final Runnable runnable = new Runnable() {
@Override
public void run() {
try {
targetSource.runModificationTask(task).commit();
}
catch ( IOException e){
Logger.getLogger( JaxWsServiceCreator.class.getCanonicalName()).
log(Level.WARNING , null , e);
}
}
};
if ( SwingUtilities.isEventDispatchThread() ){
ScanDialog.runWhenScanFinished(runnable, title);
}
else {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
ScanDialog.runWhenScanFinished(runnable, title);
}
});
}
}
else {
modificationTask.commit();
}
}
private void generateWebServiceFromEJB(String wsName, FileObject pkg, Node[] nodes) throws IOException {
if (nodes != null && nodes.length == 1) {
EjbReference ejbRef = nodes[0].getLookup().lookup(EjbReference.class);
if (ejbRef != null) {
DataFolder df = DataFolder.findFolder(pkg);
FileObject template = Templates.getTemplate(wiz);
FileObject templateParent = template.getParent();
if ((Boolean)wiz.getProperty(WizardProperties.IS_STATELESS_BEAN)) {
template = templateParent.getFileObject("EjbWebServiceNoOp", "java"); //NOI18N
} else {
template = templateParent.getFileObject("WebServiceNoOp", "java"); //NOI18N
}
DataObject dTemplate = DataObject.find(template);
DataObject dobj = dTemplate.createFromTemplate(df, wsName);
FileObject createdFile = dobj.getPrimaryFile();
/*createdFile.setAttribute("jax-ws-service", java.lang.Boolean.TRUE); // NOI18N
try {
dobj.setValid(false);
}
catch( PropertyVetoException e ){
LOG.log(Level.WARNING, null , e);
}*/
dobj = DataObject.find(createdFile);
ClassPath classPath = getClassPathForFile(project, createdFile);
if (classPath != null) {
if (classPath.findResource("javax/ejb/EJB.class") == null) { //NOI19\8N
// ad EJB API on classpath
ContainerClassPathModifier modifier = project.getLookup().lookup(ContainerClassPathModifier.class);
if (modifier != null) {
modifier.extendClasspath(createdFile, new String[] {
ContainerClassPathModifier.API_EJB
});
}
}
generateDelegateMethods(createdFile, ejbRef);
openFileInEditor(dobj);
}
}
}
}
private void generateDelegateMethods(final FileObject targetFo, final EjbReference ref) throws IOException {
final boolean[] onClassPath = new boolean[1];
final String[] interfaceClass = new String[1];
final JavaSource targetSource = JavaSource.forFileObject(targetFo);
final CancellableTask<WorkingCopy> modificationTask = new CancellableTask<WorkingCopy>() {
@Override
public void run(WorkingCopy workingCopy) throws IOException {
workingCopy.toPhase(Phase.RESOLVED);
TreeMaker make = workingCopy.getTreeMaker();
TypeElement typeElement = SourceUtils.getPublicTopLevelElement(workingCopy);
if (typeElement != null) {
VariableTree ejbRefInjection = null;
interfaceClass[0] = ref.getLocal();
if (interfaceClass[0] == null) {
interfaceClass[0] = ref.getRemote();
}
if (interfaceClass[0] == null) {
interfaceClass[0] = ref.getEjbClass();
}
ejbRefInjection = generateEjbInjection(workingCopy, make, interfaceClass[0], onClassPath);
if (ejbRefInjection != null) {
String comment1 = "Add business logic below. (Right-click in editor and choose"; //NOI18N
String comment2 = "\"Web Service > Add Operation\""; //NOI18N
make.addComment(ejbRefInjection, Comment.create(Comment.Style.LINE, 0, 0, 4, comment1), false);
make.addComment(ejbRefInjection, Comment.create(Comment.Style.LINE, 0, 0, 4, comment2), false);
ClassTree javaClass = workingCopy.getTrees().getTree(typeElement);
ClassTree modifiedClass = make.insertClassMember(javaClass, 0, ejbRefInjection);
if (onClassPath[0]) {
TypeElement beanInterface = workingCopy.getElements().getTypeElement(interfaceClass[0]);
modifiedClass = generateMethods(workingCopy, make, typeElement, modifiedClass, beanInterface);
}
workingCopy.rewrite(javaClass, modifiedClass);
}
}
}
@Override
public void cancel() {
}
};
final Runnable runnable = new Runnable() {
@Override
public void run() {
try {
targetSource.runModificationTask(modificationTask).commit();
if (!onClassPath[0]) {
DialogDisplayer.getDefault().notify(
new NotifyDescriptor.Message(
NbBundle.getMessage(JaxWsServiceCreator.class,
"MSG_EJB_NOT_ON_CLASSPATH",
interfaceClass[0], targetFo.getName()),
NotifyDescriptor.WARNING_MESSAGE));
}
}
catch( IOException e ){
Logger.getLogger(JaxWsServiceCreator.class.getCanonicalName()).
log(Level.WARNING , null, e);
}
}
};
final String title = NbBundle.getMessage(JaxWsServiceCreator.class,
"LBL_GenDelegateMethods"); // NOI18N
if ( SwingUtilities.isEventDispatchThread()){
ScanDialog.runWhenScanFinished( runnable , title);
}
else {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
ScanDialog.runWhenScanFinished( runnable , title);
}
});
}
}
private VariableTree generateEjbInjection(WorkingCopy workingCopy, TreeMaker make, String beanInterface, boolean[] onClassPath) {
TypeElement ejbAnElement = workingCopy.getElements().getTypeElement("javax.ejb.EJB"); //NOI18N
TypeElement interfaceElement = workingCopy.getElements().getTypeElement(beanInterface); //NOI18N
AnnotationTree ejbAnnotation = make.Annotation(
make.QualIdent(ejbAnElement),
Collections.<ExpressionTree>emptyList());
// create method modifier: public and no annotation
ModifiersTree methodModifiers = make.Modifiers(
Collections.<Modifier>singleton(Modifier.PRIVATE),
Collections.<AnnotationTree>singletonList(ejbAnnotation));
onClassPath[0] = interfaceElement != null;
return make.Variable(
methodModifiers,
"ejbRef", //NOI18N
onClassPath[0] ? make.Type(interfaceElement.asType()) : make.Identifier(beanInterface),
null);
}
private ClassTree generateMethods(WorkingCopy workingCopy,
TreeMaker make,
TypeElement classElement,
ClassTree modifiedClass,
TypeElement beanInterface) throws IOException {
GeneratorUtilities utils = GeneratorUtilities.get(workingCopy);
List<? extends Element> interfaceElements = beanInterface.getEnclosedElements();
TypeElement webMethodEl = workingCopy.getElements().getTypeElement("javax.jws.WebMethod"); //NOI18N
assert (webMethodEl != null);
if (webMethodEl == null) {
return modifiedClass;
}
Set<String> operationNames = new HashSet<String>();
for (Element el : interfaceElements) {
if (el.getKind() == ElementKind.METHOD) {
ExecutableElement methodEl = (ExecutableElement) el;
MethodTree method = utils.createAbstractMethodImplementation(classElement, methodEl);
Name methodName = methodEl.getSimpleName();
boolean isVoid = workingCopy.getTypes().getNoType(TypeKind.VOID) == methodEl.getReturnType();
String operationName = findUniqueOperationName(operationNames, methodName.toString());
operationNames.add(operationName);
// generate @WebMethod annotation
AssignmentTree opName = make.Assignment(make.Identifier("operationName"), make.Literal(operationName)); //NOI18N
AnnotationTree webMethodAn = make.Annotation(
make.QualIdent(webMethodEl),
Collections.<ExpressionTree>singletonList(opName));
ModifiersTree modifiersTree = make.Modifiers(
Collections.<Modifier>singleton(Modifier.PUBLIC),
Collections.<AnnotationTree>singletonList(webMethodAn));
// generate @RequestWrapper and @RequestResponse annotations
if (!methodName.contentEquals(operationName)) {
TypeElement requestWrapperEl = workingCopy.getElements().getTypeElement("javax.xml.ws.RequestWrapper"); //NOI18N
TypeElement responseWrapperEl = workingCopy.getElements().getTypeElement("javax.xml.ws.ResponseWrapper"); //NOI18N
AssignmentTree className = make.Assignment(make.Identifier("className"), make.Literal(operationName)); //NOI18N
AnnotationTree requestWrapperAn = make.Annotation(
make.QualIdent(requestWrapperEl),
Collections.<ExpressionTree>singletonList(className));
modifiersTree = make.addModifiersAnnotation(modifiersTree, requestWrapperAn);
if (!isVoid) { // only if not void
className = make.Assignment(make.Identifier("className"), make.Literal(operationName + "Response")); //NOI18N
AnnotationTree responseWrapperAn = make.Annotation(
make.QualIdent(responseWrapperEl),
Collections.<ExpressionTree>singletonList(className));
modifiersTree = make.addModifiersAnnotation(modifiersTree, responseWrapperAn);
}
}
// generate @Oneway annotation
if (isVoid && method.getThrows().isEmpty()) {
TypeElement onewayEl = workingCopy.getElements().getTypeElement("javax.jws.Oneway"); //NOI18N
AnnotationTree onewayAn = make.Annotation(
make.QualIdent(onewayEl),
Collections.<ExpressionTree>emptyList());
modifiersTree = make.addModifiersAnnotation(modifiersTree, onewayAn);
}
// parameters
List<? extends VariableTree> params = method.getParameters();
List<VariableTree> newParams = new ArrayList<VariableTree>();
if (params.size() > 0) {
TypeElement paramEl = workingCopy.getElements().getTypeElement("javax.jws.WebParam"); //NOI18N
for (VariableTree param: params) {
String paramName = param.getName().toString();
AssignmentTree nameAttr = make.Assignment(make.Identifier("name"), make.Literal(paramName)); //NOI18N
AnnotationTree paramAn = make.Annotation(
make.QualIdent(paramEl),
Collections.<ExpressionTree>singletonList(nameAttr));
ModifiersTree paramModifierTree = make.addModifiersAnnotation(param.getModifiers(), paramAn);
newParams.add(make.Variable(paramModifierTree, param.getName(), param.getType(), null));
}
}
// method body
List<ExpressionTree> arguments = new ArrayList<ExpressionTree>();
for (VariableElement ve : methodEl.getParameters()) {
arguments.add(make.Identifier(ve.getSimpleName()));
}
MethodInvocationTree inv = make.MethodInvocation(
Collections.<ExpressionTree>emptyList(),
make.MemberSelect(make.Identifier("ejbRef"), methodName), //NOI18N
arguments);
StatementTree statement = isVoid ? make.ExpressionStatement(inv) : make.Return(inv);
BlockTree body = make.Block(Collections.singletonList(statement), false);
MethodTree delegatingMethod = make.Method(
modifiersTree,
method.getName(),
method.getReturnType(),
method.getTypeParameters(),
newParams,
method.getThrows(),
body,
null);
modifiedClass = make.addClassMember(modifiedClass, delegatingMethod);
}
}
return modifiedClass;
}
private String findUniqueOperationName(Set<String> existingNames, String operationName) {
if (!existingNames.contains(operationName)) {
return operationName;
} else {
int i = 1;
String newName = operationName + "_1"; //NOI18N
while (existingNames.contains(newName)) {
newName = operationName + "_" + String.valueOf(++i); //NOI18N
}
return newName;
}
}
}