blob: 5ba3b6511bb77028e8c2b77a2cc1aed99b7937b1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Daniel Wiehl (BSI Business Systems Integration AG) - initial API and implementation
******************************************************************************/
package org.eclipse.scout.sdk.ws.jaxws.operation;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.scout.commons.CompareUtility;
import org.eclipse.scout.commons.StringUtility;
import org.eclipse.scout.sdk.operation.IOperation;
import org.eclipse.scout.sdk.util.log.ScoutStatus;
import org.eclipse.scout.sdk.util.type.TypeUtility;
import org.eclipse.scout.sdk.util.typecache.IWorkingCopyManager;
import org.eclipse.scout.sdk.workspace.IScoutBundle;
import org.eclipse.scout.sdk.ws.jaxws.JaxWsConstants;
import org.eclipse.scout.sdk.ws.jaxws.JaxWsRuntimeClasses;
import org.eclipse.scout.sdk.ws.jaxws.JaxWsSdk;
import org.eclipse.scout.sdk.ws.jaxws.preferences.IPreferenceConstants;
import org.eclipse.scout.sdk.ws.jaxws.util.JaxWsSdkUtility;
import org.eclipse.scout.sdk.ws.jaxws.util.JaxWsSdkUtility.SeparatorType;
import org.eclipse.scout.sdk.ws.jaxws.util.listener.IOperationFinishedListener;
@SuppressWarnings("restriction")
public class WsStubGenerationOperation implements IOperation {
private IScoutBundle m_bundle;
private String m_alias;
private String m_wsdlFileName;
private Map<String, List<String>> m_properties;
private String m_packageName;
private IFolder m_wsdlFolder;
private Set<IOperationFinishedListener> m_operationFinishedListeners;
public WsStubGenerationOperation() {
m_operationFinishedListeners = new HashSet<IOperationFinishedListener>();
}
public void addOperationFinishedListener(IOperationFinishedListener listener) {
m_operationFinishedListeners.add(listener);
}
public void removeOperationFinishedListener(IOperationFinishedListener listener) {
m_operationFinishedListeners.remove(listener);
}
@Override
public void validate() throws IllegalArgumentException {
if (m_bundle == null) {
throw new IllegalArgumentException("bundle not set");
}
if (m_alias == null) {
throw new IllegalArgumentException("alias not set");
}
if (m_wsdlFolder == null || !m_wsdlFolder.exists()) {
throw new IllegalArgumentException("wsdl folder not set");
}
if (m_wsdlFileName == null) {
throw new IllegalArgumentException("wsdlFileName not set");
}
}
@Override
public void run(IProgressMonitor monitor, IWorkingCopyManager workingCopyManager) throws CoreException, IllegalArgumentException {
JaxWsSdk.getDefault().getMarkerQueueManager().suspend();
try {
// ensure stub folder created
JaxWsSdkUtility.getFolder(m_bundle, JaxWsConstants.STUB_FOLDER, true);
// launch JAX-WS Stub generator
String launcherName = m_alias + " (JAX-WS stub generation)";
// ensure WSDL folder to be registered in build.xml
JaxWsSdkUtility.prepareFolderAccess(getWsdlFolder(), true);
IFile jarFile = JaxWsSdkUtility.getStubJarFile(m_bundle, m_properties, m_wsdlFileName);
// remove JAR file to ensure successful JAR generation
if (jarFile.exists()) {
try {
jarFile.delete(true, monitor);
JaxWsSdkUtility.registerJarLib(m_bundle, jarFile, true, monitor);
}
catch (Exception e) {
JaxWsSdk.logError("failed to delete jar file", e);
notifyListeners(false, new Exception("Failed to delete stub JAR-file '" + jarFile.getProjectRelativePath().toPortableString() + "'. The file might be locked because the server is running.", e));
return;
}
}
// assemble arguments to generate stub
String args = null;
String jarFilePath = JaxWsSdkUtility.normalizePath(jarFile.getProjectRelativePath().toPortableString(), SeparatorType.None);
args = StringUtility.join("\n", args, jarFilePath);
args = StringUtility.join("\n", args, getWsdlFolder().getProjectRelativePath().append(m_wsdlFileName).toPortableString());
args = StringUtility.join("\n", args, "1"); // apply patches
if (m_properties != null && m_properties.size() > 0) {
for (Entry<String, List<String>> property : m_properties.entrySet()) {
String propName = property.getKey();
if (!StringUtility.hasText(propName)) {
continue;
}
// skip not JAX-WS options
if (propName.equals(JaxWsConstants.OPTION_JAR)) {
continue;
}
List<String> propValues = property.getValue();
if (propValues == null || propValues.size() == 0) {
String directive = propName;
args = StringUtility.join("\n", args, directive);
}
else {
for (String value : propValues) {
// escape paths containing whitespace characters
if (propName.equals("b") && StringUtility.hasText(value) && value.matches(".*\\s.*") && !value.startsWith("\\")) {
value = "\"" + value + "\"";
}
String directive = StringUtility.join("=", propName, value);
args = StringUtility.join("\n", args, directive);
}
}
}
}
// run stub generation
Throwable exception = null;
try {
launchJavaApplicationSync(launcherName,
m_bundle.getProject().getName(),
TypeUtility.getType(JaxWsRuntimeClasses.JaxWsStubGenerator).getFullyQualifiedName(),
args,
monitor);
}
catch (Throwable e) {
exception = e;
}
finally {
// refresh folder to be reflected in SDK
JaxWsSdkUtility.refreshLocal(JaxWsSdkUtility.getFolder(m_bundle, JaxWsConstants.STUB_FOLDER, false), IResource.DEPTH_INFINITE);
}
if (exception == null) {
// check whether artefacts were created. This is necessary as not all failures are propagated
jarFile = JaxWsSdkUtility.getStubJarFile(m_bundle, m_properties, m_wsdlFileName);
if (JaxWsSdkUtility.exists(jarFile)) {
// register stub JAR
if (!JaxWsSdkUtility.registerJarLib(m_bundle, jarFile, false, monitor)) {
exception = new Exception("Stub generation was successfull but registration of JAR file '" + jarFilePath + "' failed in .classpath / MANIFEST.MF / build.properties");
}
}
else {
exception = new CoreException(new ScoutStatus("Failed to generate webservice artefacts. Probably a corrupt WSDL file, non-standardized WSDL file or a binding file problem."));
}
}
if (exception == null) {
notifyListeners(true, null);
}
else {
notifyListeners(false, exception);
}
}
finally {
JaxWsSdk.getDefault().getMarkerQueueManager().resume();
}
}
@Override
public String getOperationName() {
return WsStubGenerationOperation.class.getName();
}
private void launchJavaApplicationSync(String launchName, String projectName, String javaMainTypeName, String argumentList, IProgressMonitor monitor) throws Exception {
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType type = launchManager.getLaunchConfigurationType("org.eclipse.jdt.launching.localJavaApplication");
ILaunchConfigurationWorkingCopy wc = type.newInstance(null, launchName);
wc.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true);
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, projectName);
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, javaMainTypeName);
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, argumentList);
wc.setAttribute(org.eclipse.debug.internal.core.LaunchConfiguration.ATTR_MAPPED_RESOURCE_TYPES, Arrays.asList(new String[]{Integer.toString(IResource.PROJECT)}));
wc.setAttribute(org.eclipse.debug.internal.core.LaunchConfiguration.ATTR_MAPPED_RESOURCE_PATHS, Arrays.asList(new String[]{"/" + projectName}));
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, getClasspathEntries());
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, false);
wc.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
ILaunchConfiguration lc = wc.doSave();
String mode;
boolean debugMode = JaxWsSdk.getDefault().getPreferenceStore().getBoolean(IPreferenceConstants.PREF_STUB_GENERATION_DEBUG_MODE);
if (debugMode) {
mode = ILaunchManager.DEBUG_MODE;
}
else {
mode = ILaunchManager.RUN_MODE;
}
String continueWithCompileErros = DebugUIPlugin.getDefault().getPreferenceStore().getString(IInternalDebugUIConstants.PREF_CONTINUE_WITH_COMPILE_ERROR);
boolean changedDebugPref = false;
try {
if (!CompareUtility.equals(MessageDialogWithToggle.ALWAYS, continueWithCompileErros)) {
// prevent PDE dialog asking whether to continue in case of compile errors
DebugUIPlugin.getDefault().getPreferenceStore().setValue(IInternalDebugUIConstants.PREF_CONTINUE_WITH_COMPILE_ERROR, MessageDialogWithToggle.ALWAYS);
changedDebugPref = true;
}
ILaunch launch = lc.launch(mode, monitor, true, true);
// wait for stub generation to be finished
while (!launch.isTerminated()) {
if (monitor.isCanceled()) {
launch.terminate();
break;
}
Thread.sleep(1000);
}
boolean keepLaunchConfiguration = JaxWsSdk.getDefault().getPreferenceStore().getBoolean(IPreferenceConstants.PREF_STUB_GENERATION_KEEP_LAUNCH_CONFIG);
if (!keepLaunchConfiguration) {
lc.delete();
}
// validate exit code of processes
for (IProcess process : launch.getProcesses()) {
if (process.getExitValue() != 0) {
new CoreException(new ScoutStatus("Stub generation failed"));
}
}
}
finally {
if (changedDebugPref) {
DebugUIPlugin.getDefault().getPreferenceStore().setValue(IInternalDebugUIConstants.PREF_CONTINUE_WITH_COMPILE_ERROR, continueWithCompileErros);
}
}
}
private void notifyListeners(boolean success, Throwable exception) {
for (IOperationFinishedListener listener : m_operationFinishedListeners.toArray(new IOperationFinishedListener[m_operationFinishedListeners.size()])) {
try {
listener.operationFinished(success, exception);
}
catch (Exception e) {
JaxWsSdk.logError("failed to notify listener", e);
}
}
}
private boolean isSuccess(IProcess[] processes) throws DebugException {
for (IProcess process : processes) {
if (process.getExitValue() != 0) {
return false;
}
}
return true;
}
private List<String> getClasspathEntries() throws Exception {
List<String> mementoList = new LinkedList<String>();
// add runtime classes to the classpath
for (IRuntimeClasspathEntry classpathEntry : JavaRuntime.computeUnresolvedRuntimeClasspath(m_bundle.getJavaProject())) {
mementoList.add(classpathEntry.getMemento());
}
// check whether the required lib tools.jar is part of the workspace classpath (required for WsImport)
IType wsImportType = TypeUtility.getType(JaxWsRuntimeClasses.WsImportType);
if (wsImportType == null || !wsImportType.exists() || !TypeUtility.isOnClasspath(wsImportType, m_bundle.getJavaProject())) {
// manually add tool.jar to the classpath of the launch-configuration (from JRE).
File toolsJarFile = locateToolsJar();
if (toolsJarFile == null || !toolsJarFile.exists() || !toolsJarFile.isFile()) {
throw new CoreException(new ScoutStatus("Could not locate the Java library 'tools.jar'. Please ensure to have the environment variable JAVA_HOME set and the JAR /lib/tools.jar exists. Alternatively, add the JAR 'tools.jar' to the system libraries of the installed JRE in Eclipse Preferences 'Java | Installed JREs'."));
}
mementoList.add(JavaRuntime.newArchiveRuntimeClasspathEntry(new Path(toolsJarFile.getAbsolutePath())).getMemento());
}
return mementoList;
}
private File locateToolsJar() {
String[] defaultToolsLocation = {"lib", "tools.jar"};
File file = new File(System.getProperty("java.home"));
if (file.getName().equalsIgnoreCase("jre")) {
file = file.getParentFile();
}
for (String name : defaultToolsLocation) {
file = new File(file, name);
}
return file;
}
public IScoutBundle getBundle() {
return m_bundle;
}
public void setBundle(IScoutBundle bundle) {
m_bundle = bundle;
}
public String getAlias() {
return m_alias;
}
public void setAlias(String alias) {
m_alias = alias;
}
public String getWsdlFileName() {
return m_wsdlFileName;
}
public IFolder getWsdlFolder() {
return m_wsdlFolder;
}
public void setWsdlFolder(IFolder wsdlFolder) {
m_wsdlFolder = wsdlFolder;
}
public void setWsdlFileName(String wsdlFileName) {
m_wsdlFileName = wsdlFileName;
}
public void setProperties(Map<String, List<String>> properties) {
m_properties = properties;
}
}