blob: 755d63094a62d6eede309c015476af25817c7bb2 [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.web.project.jaxws;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.j2ee.core.Profile;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.libraries.Library;
import org.netbeans.api.project.libraries.LibraryManager;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.modules.j2ee.common.dd.DDHelper;
import org.netbeans.modules.j2ee.core.api.support.SourceGroups;
import org.netbeans.modules.j2ee.dd.api.common.NameAlreadyUsedException;
import org.netbeans.modules.j2ee.dd.api.web.DDProvider;
import org.netbeans.modules.j2ee.dd.api.web.Listener;
import org.netbeans.modules.j2ee.dd.api.web.Servlet;
import org.netbeans.modules.j2ee.dd.api.web.ServletMapping;
import org.netbeans.modules.j2ee.dd.api.web.WebApp;
import org.netbeans.modules.j2ee.dd.api.webservices.WebservicesMetadata;
import org.netbeans.modules.j2ee.deployment.devmodules.api.Deployment;
import org.netbeans.modules.j2ee.deployment.devmodules.api.J2eePlatform;
import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel;
import org.netbeans.modules.web.api.webmodule.WebModule;
import org.netbeans.modules.web.project.WebProject;
import org.netbeans.modules.web.project.WebProjectWebServicesSupport;
import org.netbeans.modules.websvc.api.jaxws.project.LogUtils;
import org.netbeans.modules.websvc.api.jaxws.project.WSUtils;
import org.netbeans.modules.websvc.api.jaxws.project.config.Endpoint;
import org.netbeans.modules.websvc.api.jaxws.project.config.Endpoints;
import org.netbeans.modules.websvc.api.jaxws.project.config.EndpointsProvider;
import org.netbeans.modules.websvc.api.jaxws.project.config.JaxWsModel;
import org.netbeans.modules.websvc.api.jaxws.project.config.Service;
import org.netbeans.modules.websvc.jaxws.api.JAXWSSupport;
import org.netbeans.modules.websvc.jaxws.spi.ProjectJAXWSSupport;
import org.netbeans.spi.project.support.ant.AntProjectHelper;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
*
* @author mkuchtiak
*/
public class WebProjectJAXWSSupport extends ProjectJAXWSSupport /*implements JAXWSSupportImpl*/ {
private WebProject project;
//servlet name and servlet listener for non-JSR 109 web services
private static final String servletClassName = "com.sun.xml.ws.transport.http.servlet.WSServlet"; //NOI18N
private static final String servletListener = "com.sun.xml.ws.transport.http.servlet.WSServletContextListener"; //NOI18N
/** Creates a new instance of JAXWSSupport */
public WebProjectJAXWSSupport(WebProject project, AntProjectHelper antProjectHelper) {
super(project,antProjectHelper);
this.project = project;
}
@Override
public FileObject getWsdlFolder(boolean create) throws java.io.IOException {
WebModule webModule = WebModule.getWebModule(project.getProjectDirectory());
if (webModule!=null) {
FileObject webInfFo = webModule.getWebInf();
if (webInfFo!=null) {
FileObject wsdlFo = webInfFo.getFileObject("wsdl"); //NOI18N
if (wsdlFo!=null) return wsdlFo;
else if (create) {
return webInfFo.createFolder("wsdl"); //NOI18N
}
}
}
return null;
}
/** Get wsdlLocation information
* Useful for web service from wsdl
* @param name service "display" name
*/
@Override
public String getWsdlLocation(String serviceName) {
String localWsdl = serviceName+".wsdl"; //NOI18N
JaxWsModel jaxWsModel = (JaxWsModel)project.getLookup().lookup(JaxWsModel.class);
if (jaxWsModel!=null) {
Service service = jaxWsModel.findServiceByName(serviceName);
if (service!=null) {
String localWsdlFile = service.getLocalWsdlFile();
if (localWsdlFile!=null) localWsdl=localWsdlFile;
}
}
String prefix = "WEB-INF/wsdl/"; //NOI18N
return prefix+serviceName+"/"+localWsdl; //NOI18N
}
/**
* This is to support non-JSR 109 containers. In this case, a regular jaxws web service
* is created and the deployment descriptor is updated with the jaxws-ri servlet and
* listener.
*/
private void addServiceEntriesToDD(String serviceName) {
//add servlet entry to web.xml
String servletName = serviceName;
WebApp webApp = getWebApp();
if(webApp != null){
Servlet servlet;
try{
servlet = (Servlet)webApp.addBean("Servlet", new String[]{"ServletName","ServletClass"},
new Object[]{servletName,servletClassName}, "ServletName");
servlet.setLoadOnStartup(new java.math.BigInteger("1"));
webApp.addBean("ServletMapping", new String[]{"ServletName","UrlPattern"},
new Object[]{servletName, "/" + serviceName}, "ServletName");
if(!webAppHasListener(webApp, servletListener)){
webApp.addBean("Listener", new String[]{"ListenerClass"},
new Object[]{servletListener}, "ListenerClass");
}
// This also saves server specific configuration, if necessary.
webApp.write(getDeploymentDescriptor());
} catch (ClassNotFoundException exc) {
Logger.getLogger("global").log(Level.INFO, exc.getLocalizedMessage());
} catch (NameAlreadyUsedException exc) {
Logger.getLogger("global").log(Level.INFO, exc.getLocalizedMessage());
} catch (IOException exc) {
Logger.getLogger("global").log(Level.INFO, exc.getLocalizedMessage());
}
}
}
@Override
protected void addServletElement(Project project, String wsName, String serviceImpl) throws IOException {
WebApp webApp = getWebApp();
if(webApp != null) {
boolean addServletEntry = false;
JAXWSSupport wss = JAXWSSupport.getJAXWSSupport(project.getProjectDirectory());
if (wss != null) {
Map properties = wss.getAntProjectHelper().getStandardPropertyEvaluator().getProperties();
if (properties != null) {
String serverInstance = (String)properties.get("j2ee.server.instance"); //NOI18N
if (serverInstance != null) {
J2eePlatform j2eePlatform = Deployment.getDefault().getJ2eePlatform(serverInstance);
if (j2eePlatform != null) {
if (j2eePlatform.isToolSupported("JaxWs-in-j2ee14-supported")) addServletEntry = true;
}
}
}
}
if (addServletEntry) {
try{
Servlet servlet = (Servlet)webApp.addBean("Servlet", new String[]{"ServletName","ServletClass"},
new Object[]{wsName,serviceImpl}, "ServletName");
servlet.setLoadOnStartup(new java.math.BigInteger("1"));
webApp.addBean("ServletMapping", new String[]{"ServletName","UrlPattern"},
new Object[]{wsName, "/" + wsName}, "UrlPattern");
// This also saves server specific configuration, if necessary.
webApp.write(getDeploymentDescriptor());
} catch (ClassNotFoundException exc) {
Logger.getLogger("global").log(Level.INFO, exc.getLocalizedMessage());
} catch (NameAlreadyUsedException exc) {
Logger.getLogger("global").log(Level.INFO, exc.getLocalizedMessage());
}
}
}
}
/**
* Remove the web.xml entries for the non-JSR 109 web service.
*
* @param serviceName Name of the web service to be removed
*/
private void removeServiceEntriesFromDD(String serviceName) {
WebApp webApp = getWebApp();
if (webApp != null) {
boolean changed = removeNonJsr109ServletsFromDD(webApp, serviceName);
//determine if there are other web services in the project
//if none, remove the listener
boolean hasMoreWebServices = false;
Servlet[] remainingServlets = webApp.getServlet();
for(int i = 0; i < remainingServlets.length; i++){
if(remainingServlets[i].getServletClass().equals(servletClassName)){
hasMoreWebServices = true;
break;
}
}
if(!hasMoreWebServices){
Listener[] listeners = webApp.getListener();
for(int i = 0; i < listeners.length; i++){
Listener listener = listeners[i];
if(listener.getListenerClass().equals(servletListener)){
webApp.removeListener(listener);
changed = true;
break;
}
}
}
if(changed){
try{
webApp.write(getDeploymentDescriptor());
} catch(IOException e){
Exceptions.printStackTrace(e);
}
}
}
}
/**
* Remove the web.xml servlets for the non-JSR 109 web service.
*
* @param serviceName Name of the web service to be removed
*/
private boolean removeNonJsr109ServletsFromDD(WebApp webApp, String serviceName) {
boolean changed = false;
//first remove the servlet
Servlet[] servlets = webApp.getServlet();
for(int i = 0; i < servlets.length; i++){
Servlet servlet = servlets[i];
if(servlet.getServletName().equals(serviceName)){
webApp.removeServlet(servlet);
changed = true;
break;
}
}
//remove the servlet mapping
ServletMapping[] mappings = webApp.getServletMapping();
for(int i = 0; i < mappings.length; i++){
ServletMapping mapping = mappings[i];
if(mapping.getServletName().equals(serviceName)){
webApp.removeServletMapping(mapping);
changed = true;
}
}
return changed;
}
private boolean webAppHasListener(WebApp webApp, String listenerClass){
Listener[] listeners = webApp.getListener();
for(int i = 0; i < listeners.length; i++){
Listener listener = listeners[i];
if(listenerClass.equals(listener.getListenerClass())){
return true;
}
}
return false;
}
/**
* Returns the directory that contains the deployment descriptor in the project
*/
@Override
public FileObject getDeploymentDescriptorFolder() {
WebModule webModule = WebModule.getWebModule(project.getProjectDirectory());
if(webModule != null) {
return webModule.getWebInf();
}
return null;
}
private WebApp getWebApp() {
try {
FileObject deploymentDescriptor = getDeploymentDescriptor();
if(deploymentDescriptor != null) {
return DDProvider.getDefault().getDDRoot(deploymentDescriptor);
}
} catch (java.io.IOException e) {
Logger.getLogger("global").log(Level.INFO, e.getLocalizedMessage());
}
return null;
}
private boolean isProjectOpened() {
// XXX workaround: OpenProjects.getDefault() can be null
// when called from ProjectOpenedHook.projectOpened() upon IDE startup
if (OpenProjects.getDefault() == null) {
return true;
}
Project[] projects = OpenProjects.getDefault().getOpenProjects();
for (int i = 0; i < projects.length; i++) {
if (projects[i].equals(project)) {
return true;
}
}
return false;
}
private FileObject getDeploymentDescriptor() throws IOException {
WebModule webModule = WebModule.getWebModule(project.getProjectDirectory());
if (webModule != null) {
FileObject ddFo = webModule.getDeploymentDescriptor();
if (ddFo == null) {
FileObject webInfFo = webModule.getWebInf();
if (webInfFo != null) {
ddFo = DDHelper.createWebXml(webModule.getJ2eeProfile(), webInfFo);
}
}
return ddFo;
} else {
DialogDisplayer.getDefault().notify(
new NotifyDescriptor.Message(NbBundle.getMessage(WebProjectWebServicesSupport.class,"MSG_WebInfCorrupted"), // NOI18N
NotifyDescriptor.ERROR_MESSAGE));
return null;
}
}
@Override
protected void addJaxwsArtifacts(Project project, String wsName, String serviceImpl) throws Exception {
// check if the wsimport class is already present - this means we don't need to add the library
SourceGroup[] sgs = SourceGroups.getJavaSourceGroups(project);
if (sgs.length > 0) {
ClassPath classPath = ClassPath.getClassPath(sgs[0].getRootFolder(),ClassPath.COMPILE);
if (classPath != null) {
FileObject wsimportFO = classPath.findResource("com/sun/tools/ws/ant/WsImport.class"); // NOI18N
if (wsimportFO == null) {
//Add the Metro library to the project to be packed with the archive
Library metroLib = LibraryManager.getDefault().getLibrary("metro"); //NOI18N
if (metroLib != null) {
try {
ProjectClassPathModifier.addLibraries(
new Library[] {metroLib},
sgs[0].getRootFolder(),
ClassPath.COMPILE);
}catch(IOException e){
throw new Exception("Unable to add Metro library", e);
}
} else {
throw new Exception("Unable to add Metro Library"); //NOI18N
}
}
}
}
//Add the servlet and listener entry in web.xml
addServiceEntriesToDD(wsName);
//create the sun-jaxws deployment descriptor
FileObject ddFolder = getDeploymentDescriptorFolder();
if(ddFolder != null){
FileObject sunjaxwsFile = ddFolder.getFileObject("sun-jaxws.xml");
if(sunjaxwsFile == null){
WSUtils.generateSunJaxwsFile(ddFolder);
}
sunjaxwsFile = ddFolder.getFileObject("sun-jaxws.xml");
Endpoints endpoints = EndpointsProvider.getDefault().getEndpoints(sunjaxwsFile);
Endpoint endpoint = endpoints.newEndpoint();
endpoint.setEndpointName(wsName);
endpoint.setImplementation(serviceImpl);
endpoint.setUrlPattern("/" + wsName);
endpoints.addEnpoint(endpoint);
FileLock lock = null;
OutputStream os = null;
synchronized (this) {
try{
lock = sunjaxwsFile.lock();
os = sunjaxwsFile.getOutputStream(lock);
endpoints.write(os);
}finally{
if(lock != null) {
lock.releaseLock();
}
if(os != null) {
os.close();
}
}
}
}else{
String mes = NbBundle.getMessage(WebProjectJAXWSSupport.class, "MSG_CannotFindWEB-INF"); // NOI18N
NotifyDescriptor desc = new NotifyDescriptor.Message(mes, NotifyDescriptor.Message.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(desc);
}
}
/** return root folder for xml artifacts
*/
@Override
protected FileObject getXmlArtifactsRoot() {
return project.getWebModule().getConfDir();
}
/**
* Notification when Service (created from java) is removed from jax-ws.xml
* (JAXWSSupport needs to react when @WebService annotation is removed
* or when impl.class is removed (manually from project)
* Default implementation does nothing.
*/
@Override
public void serviceFromJavaRemoved(String serviceName) {
JaxWsModel jaxWsModel = (JaxWsModel)project.getLookup().lookup(JaxWsModel.class);
Boolean isJsr109 = jaxWsModel.getJsr109();
if(isJsr109!=null && !isJsr109){
try{
removeNonJsr109Entries(serviceName);
}catch(IOException e){
Exceptions.printStackTrace(e);
}
} else {
try{
removeJsr109Entries(serviceName);
}catch(IOException e){
Exceptions.printStackTrace(e);
}
}
}
/**
* Removes the servlet entry from web.xml and
* the endpoint entry from the sun-jaxws.xml file
*/
@Override
public void removeNonJsr109Entries(String serviceName) throws IOException {
//delete web.xml entry
removeServiceEntriesFromDD(serviceName);
//delete entry in sun-jaxws.xml file.
FileObject ddFolder = getDeploymentDescriptorFolder();
if(ddFolder != null){
FileObject sunjaxwsFile = ddFolder.getFileObject("sun-jaxws.xml");
if(sunjaxwsFile != null){
FileLock lock = null;
//if there are no more services, delete the file
JaxWsModel jaxWsModel = (JaxWsModel)project.getLookup().lookup(JaxWsModel.class);
if(jaxWsModel.getServices().length == 0) {
synchronized(this) {
try{
lock = sunjaxwsFile.lock();
sunjaxwsFile.delete(lock);
} finally{
if(lock != null){
lock.releaseLock();
}
}
}
} else{
//remove the entry from the sunjaxwsFile
Endpoints endpoints = EndpointsProvider.getDefault().getEndpoints(sunjaxwsFile);
Endpoint endpoint = endpoints.findEndpointByName(serviceName);
if(endpoint != null){
endpoints.removeEndpoint(endpoint);
OutputStream os = null;
synchronized(this) {
try{
lock = sunjaxwsFile.lock();
os = sunjaxwsFile.getOutputStream(lock);
endpoints.write(os);
}finally{
if(lock != null){
lock.releaseLock();
}
if(os != null){
os.close();
}
}
}
}
}
}
}else{
String mes = NbBundle.getMessage(WebProjectJAXWSSupport.class, "MSG_CannotFindDDDirectory"); // NOI18N
NotifyDescriptor desc = new NotifyDescriptor.Message(mes, NotifyDescriptor.Message.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(desc);
}
//TODO if no more web services, remove the jaxws21 library
}
/**
* Removes the servlet entry from web.xml and
* the endpoint entry from the sun-jaxws.xml file
*/
public void removeJsr109Entries(String serviceName) throws IOException {
WebApp webApp = getWebApp();
if (webApp != null) {
JaxWsModel jaxWsModel = (JaxWsModel)project.getLookup().lookup(JaxWsModel.class);
if (jaxWsModel != null) {
Service service = jaxWsModel.findServiceByName(serviceName);
if (service != null) {
boolean changed = removeJsr109ServletsFromDD(webApp, service);
if(changed){
try{
webApp.write(getDeploymentDescriptor());
} catch(IOException e){
Exceptions.printStackTrace(e);
}
}
}
}
}
}
/**
* Remove the web.xml servlets for the non-JSR 109 web service.
*
* @param serviceName Name of the web service to be removed
*/
private boolean removeJsr109ServletsFromDD(WebApp webApp, Service service) {
boolean changed = false;
//first remove the servlet
String implClass = service.getImplementationClass();
if (implClass != null) {
String servletName = null;
for(Servlet servlet:webApp.getServlet()){
if(implClass.equals(servlet.getServletClass())) {
webApp.removeServlet(servlet);
servletName = servlet.getServletName();
changed = true;
break;
}
}
//remove the servlet mapping
if (servletName != null) {
for(ServletMapping mapping:webApp.getServletMapping()) {
if(mapping.getServletName().equals(servletName)){
webApp.removeServletMapping(mapping);
changed = true;
break;
}
}
}
}
return changed;
}
@Override
public String addService(String name, String serviceImpl, String wsdlUrl, String serviceName,
String portName, String packageName, boolean isJsr109, boolean useProvider) {
// create jax-ws.xml if necessary
FileObject fo = WSUtils.findJaxWsFileObject(project);
if (fo==null) {
try {
WSUtils.createJaxWsFileObject(project);
// logging first service creation
logWsDetected();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
return super.addService(name, serviceImpl, wsdlUrl, serviceName, portName, packageName, isJsr109, useProvider);
}
@Override
public void addService(String serviceName, String serviceImpl, boolean isJsr109) {
// create jax-ws.xml if necessary
FileObject fo = WSUtils.findJaxWsFileObject(project);
if (fo==null) {
try {
WSUtils.createJaxWsFileObject(project);
// logging first service creation
logWsDetected();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
super.addService(serviceName, serviceImpl, isJsr109);
}
@Override
public MetadataModel<WebservicesMetadata> getWebservicesMetadataModel() {
return project.getWebModule().getWebservicesMetadataModel();
}
private void logWsDetected() {
Object[] params = new Object[3];
params[0] = LogUtils.WS_STACK_JAXWS;
params[1] = project.getClass().getName();
params[2] = "SERVICE"; // NOI18N
LogUtils.logWsDetect(params);
}
@Override
protected String getProjectJavaEEVersion() {
WebModule webModule = WebModule.getWebModule(project.getProjectDirectory());
if (webModule != null) {
if (Profile.JAVA_EE_6_WEB.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_16;
} else if (Profile.JAVA_EE_6_FULL.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_16;
} else if (Profile.JAVA_EE_7_WEB.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_17;
} else if (Profile.JAVA_EE_7_FULL.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_17;
} else if (Profile.JAVA_EE_8_WEB.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_18;
} else if (Profile.JAVA_EE_8_FULL.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_18;
} else if (Profile.JAKARTA_EE_8_WEB.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_8;
} else if (Profile.JAKARTA_EE_8_FULL.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_8;
} else if (Profile.JAKARTA_EE_9_WEB.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_9;
} else if (Profile.JAKARTA_EE_9_FULL.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_9;
} else if (Profile.JAKARTA_EE_9_1_WEB.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_91;
} else if (Profile.JAKARTA_EE_9_1_FULL.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_91;
} else if (Profile.JAKARTA_EE_10_WEB.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_10;
} else if (Profile.JAKARTA_EE_10_FULL.equals(webModule.getJ2eeProfile())) {
return JAKARTA_EE_VERSION_10;
} else if (Profile.JAVA_EE_5.equals(webModule.getJ2eeProfile())) {
return JAVA_EE_VERSION_15;
}
}
return JAVA_EE_VERSION_NONE;
}
}