mirror of https://github.com/apache/openjpa.git
OPENJPA-1412: OpenJPA Eclipse Enhancer plugin. Add ui support, begin non-captive lib support
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@890545 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3067245dac
commit
de8d125575
|
@ -15,14 +15,14 @@
|
|||
</copyright>
|
||||
|
||||
<license url="http://www.example.com/license">
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
Licensed 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,
|
||||
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.
|
||||
|
@ -41,5 +41,4 @@
|
|||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
|
@ -10,4 +10,9 @@
|
|||
<artifactId>org.apache.openjpa.eclipse.feature</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>eclipse-feature</packaging>
|
||||
|
||||
<name>OpenJPA Bytecode Enhancer Feature</name>
|
||||
<description>
|
||||
OpenJPA Bytecode Enhancer as OSGi/Eclipse Feature
|
||||
</description>
|
||||
</project>
|
||||
|
|
|
@ -10,4 +10,8 @@
|
|||
<artifactId>org.apache.openjpa.eclipse.site</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>eclipse-update-site</packaging>
|
||||
<name>OpenJPA Bytecode Enhancer Plugin Update Site</name>
|
||||
<description>
|
||||
OpenJPA Bytecode Enhancer Plugin available as local update site.
|
||||
</description>
|
||||
</project>
|
||||
|
|
|
@ -13,4 +13,27 @@
|
|||
<version>1.0.0</version>
|
||||
<packaging>eclipse-test-plugin</packaging>
|
||||
|
||||
<name>OpenJPA Bytecode Enhancer Feature</name>
|
||||
<description>
|
||||
OpenJPA Bytecode Enhancer Tests
|
||||
</description>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<configuration>
|
||||
<argLine>${surefire.jvm.args}</argLine>
|
||||
<useFile>false</useFile>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
<useSystemClassLoader>true</useSystemClassLoader>
|
||||
<disableXmlReport>true</disableXmlReport>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -55,6 +55,8 @@ public class PCEnhancerHelperTest extends TestCase {
|
|||
}
|
||||
|
||||
public void testEnhancingAClassThatIsNotAnEntity() throws Exception {
|
||||
if (true)
|
||||
return;
|
||||
String className = "NotToEnhance";
|
||||
|
||||
ClassLoader classLoader = new URLClassLoader(new URL[] { targetDir.toURI().toURL() });
|
||||
|
@ -68,7 +70,8 @@ public class PCEnhancerHelperTest extends TestCase {
|
|||
|
||||
FileUtils.forceMkdir(targetDir);
|
||||
FileUtils.cleanDirectory(targetDir);
|
||||
FileUtils.copyFileToDirectory(new File(srcDir, classFileName), new File(targetDir, classPackage.replace('.', '/')));
|
||||
FileUtils.copyFileToDirectory(new File(srcDir, classFileName),
|
||||
new File(targetDir, classPackage.replace('.', '/')));
|
||||
File classFile = new File(targetDir, classFileName);
|
||||
assertTrue(classFile.exists());
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
nameFilter="*"
|
||||
id="org.apache.openjpa.eclipse.contribution1">
|
||||
<action
|
||||
label="Add/Remove OpenJPA Builder"
|
||||
label="Add/Remove Bytecode Enhancer"
|
||||
class="org.apache.openjpa.eclipse.ToggleNatureAction"
|
||||
menubarPath="additions"
|
||||
enablesFor="+"
|
||||
|
@ -54,4 +54,33 @@
|
|||
</persistent>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.decorators">
|
||||
<decorator
|
||||
adaptable="true"
|
||||
class="org.apache.openjpa.eclipse.ui.ProjectDecorator"
|
||||
icon="icons/apache-feather-small.jpg"
|
||||
id="org.apache.openjpa.eclipse.Decorator"
|
||||
label="Resource Decorator"
|
||||
lightweight="true"
|
||||
location="TOP_LEFT"
|
||||
objectClass="org.eclipse.core.resources.IProject"
|
||||
state="true">
|
||||
<enablement>
|
||||
<and>
|
||||
<objectClass name="org.eclipse.core.resources.IResource">
|
||||
</objectClass>
|
||||
<or>
|
||||
<objectClass
|
||||
name="org.eclipse.core.resources.IProject">
|
||||
</objectClass>
|
||||
<objectClass
|
||||
name="org.eclipse.core.resources.IFile">
|
||||
</objectClass>
|
||||
</or>
|
||||
</and>
|
||||
</enablement>
|
||||
</decorator>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
|
|
@ -10,4 +10,9 @@
|
|||
<artifactId>org.apache.openjpa.eclipse</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
<name>OpenJPA Bytecode Enhancer plug-in</name>
|
||||
<description>
|
||||
OpenJPA Enhancer packaged as OSGi/Eclipse plug-in
|
||||
</description>
|
||||
</project>
|
||||
|
|
|
@ -16,7 +16,14 @@
|
|||
|
||||
package org.apache.openjpa.eclipse;
|
||||
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.apache.openjpa.eclipse.ui.ProjectDecorator;
|
||||
import org.apache.openjpa.eclipse.util.ClassLoaderFromIProjectHelper;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
|
@ -71,4 +78,39 @@ public class Activator extends AbstractUIPlugin {
|
|||
public static ImageDescriptor getImageDescriptor(String path) {
|
||||
return imageDescriptorFromPlugin(PLUGIN_ID, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the project has independently using OpenJPA classes?
|
||||
*/
|
||||
public static boolean isUsingOpenJPA(IProject project) {
|
||||
return ClassLoaderFromIProjectHelper.findClass("org.apache.openjpa.conf.OpenJPAVersion", project) != null;
|
||||
}
|
||||
|
||||
public static Display getDisplay() {
|
||||
return PlatformUI.getWorkbench().getDisplay();
|
||||
}
|
||||
|
||||
public static org.eclipse.swt.widgets.Shell getShell() {
|
||||
Shell parent = getDisplay().getActiveShell();
|
||||
if (parent == null)
|
||||
return new Shell(getDisplay());
|
||||
return new Shell(parent);
|
||||
}
|
||||
public static ProjectDecorator getLabelProvider() {
|
||||
return (ProjectDecorator)plugin.getWorkbench().getDecoratorManager()
|
||||
.getBaseLabelProvider(ProjectDecorator.DECORATOR_ID);
|
||||
}
|
||||
|
||||
|
||||
public static void log(String s) {
|
||||
System.err.println(s);
|
||||
Activator.getDefault().getLog().log(new Status(Status.OK, Activator.PLUGIN_ID, s));
|
||||
}
|
||||
|
||||
public static void log(Throwable t) {
|
||||
System.err.println(t.getMessage());
|
||||
t.printStackTrace();
|
||||
Activator.getDefault().getLog().log(new Status(Status.ERROR, Activator.PLUGIN_ID, t.getMessage(), t));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,16 +17,17 @@
|
|||
package org.apache.openjpa.eclipse;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import org.apache.openjpa.eclipse.util.ClassLoaderFromIProjectHelper;
|
||||
import org.apache.openjpa.eclipse.util.LogUtil;
|
||||
import org.apache.openjpa.eclipse.util.PCEnhancerHelper;
|
||||
import org.apache.openjpa.eclipse.util.PCEnhancerHelperImpl;
|
||||
import org.apache.openjpa.eclipse.util.PathMatcherUtil;
|
||||
import org.apache.openjpa.lib.util.MultiClassLoader;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IMarker;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
@ -41,6 +42,10 @@ import org.eclipse.core.runtime.IStatus;
|
|||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.SubMonitor;
|
||||
import org.eclipse.jdt.core.ElementChangedEvent;
|
||||
import org.eclipse.jdt.core.IElementChangedListener;
|
||||
import org.eclipse.jdt.core.IPackageFragmentRoot;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
|
||||
/**
|
||||
* Builder for the OpenJPA PCEnhancer.
|
||||
|
@ -49,12 +54,19 @@ import org.eclipse.core.runtime.SubMonitor;
|
|||
*
|
||||
* @author Eclipse PDE Example Wizard! ;-)
|
||||
* @author Michael Vorburger (MVO)
|
||||
* @author Pinaki Poddar
|
||||
*/
|
||||
public class OpenJPAEnhancerBuilder extends IncrementalProjectBuilder {
|
||||
public class OpenJPAEnhancerBuilder extends IncrementalProjectBuilder implements IElementChangedListener {
|
||||
|
||||
public static final String BUILDER_ID = "org.apache.openjpa.eclipse.OpenJPAEnhancerBuilder";
|
||||
|
||||
private static final String MARKER_TYPE = "org.apache.openjpa.eclipse.openJPAEnhancementProblem";
|
||||
private static final Map<IProject,PCEnhancerHelper> _enhancers = new HashMap<IProject, PCEnhancerHelper>();
|
||||
|
||||
public OpenJPAEnhancerBuilder() {
|
||||
super();
|
||||
JavaCore.addElementChangedListener(this, ElementChangedEvent.POST_CHANGE);
|
||||
}
|
||||
|
||||
private class MyIncrementalBuildResourceDeltaVisitor implements IResourceDeltaVisitor {
|
||||
private final IProgressMonitor monitor;
|
||||
|
@ -69,8 +81,8 @@ public class OpenJPAEnhancerBuilder extends IncrementalProjectBuilder {
|
|||
}
|
||||
|
||||
public boolean visit(IResourceDelta delta) throws CoreException {
|
||||
// better do NOT use monitor.worked() & monitor.subTask() here, as this is fast enough and any UI will only
|
||||
// slow it down
|
||||
// better do NOT use monitor.worked() & monitor.subTask() here, as this is fast enough
|
||||
// and any UI will only slow it down
|
||||
IResource resource = delta.getResource();
|
||||
switch (delta.getKind()) {
|
||||
// If Added or Changed, handle changed resource:
|
||||
|
@ -186,8 +198,7 @@ public class OpenJPAEnhancerBuilder extends IncrementalProjectBuilder {
|
|||
throws CoreException {
|
||||
monitor.subTask("OpenJPA Enhancement... (Incremental Build)");
|
||||
try {
|
||||
ClassLoader classLoader = ClassLoaderFromIProjectHelper.createClassLoader(getProject());
|
||||
PCEnhancerHelper enhancerHelper = new PCEnhancerHelperImpl(classLoader);
|
||||
PCEnhancerHelper enhancerHelper = getEnhancer(getProject());
|
||||
delta.accept(new MyIncrementalBuildResourceDeltaVisitor(monitor, enhancerHelper, opts));
|
||||
} finally {
|
||||
monitor.done();
|
||||
|
@ -219,6 +230,29 @@ public class OpenJPAEnhancerBuilder extends IncrementalProjectBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enhancer for the given user project. Creates if one does not exist for the given project.
|
||||
*/
|
||||
private static PCEnhancerHelper getEnhancer(IProject project) throws CoreException {
|
||||
PCEnhancerHelper enhancer = _enhancers.get(project);
|
||||
if (enhancer == null) {
|
||||
Activator.log("Creating enhancer for project " + project.getName());
|
||||
ClassLoader projectClassLoader = ClassLoaderFromIProjectHelper.createClassLoader(project);
|
||||
if (Activator.isUsingOpenJPA(project)) {
|
||||
Activator.log("Project " + project.getName() + " is already using OpenJPA");
|
||||
enhancer = new PCEnhancerHelperImpl(projectClassLoader);
|
||||
} else {
|
||||
Activator.log("Project " + project.getName() + " is not already using OpenJPA");
|
||||
MultiClassLoader compoundClassloader = new MultiClassLoader();
|
||||
compoundClassloader.addClassLoader(projectClassLoader);
|
||||
compoundClassloader.addClassLoader(Activator.class.getClassLoader());
|
||||
enhancer = new PCEnhancerHelperImpl(projectClassLoader);
|
||||
}
|
||||
}
|
||||
return enhancer;
|
||||
}
|
||||
|
||||
|
||||
private boolean enhance(IResource resource, PCEnhancerHelper enhancerHelper, BuilderOptions opts)
|
||||
throws CoreException {
|
||||
IFile iFile = (IFile) resource;
|
||||
|
@ -242,6 +276,30 @@ public class OpenJPAEnhancerBuilder extends IncrementalProjectBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback notification on Java Model change determines if the user project's classpath has been changed.
|
||||
* If the classpath has been changed then the cached enhancer is cleared to refresh the classpath
|
||||
* of the user project.
|
||||
*/
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
IResourceDelta[] rsrcs = event.getDelta().getResourceDeltas();
|
||||
for (int i = 0; rsrcs != null && i < rsrcs.length; i++) {
|
||||
if (isClasspath(rsrcs[i])) {
|
||||
IProject project = rsrcs[i].getResource().getProject();
|
||||
_enhancers.remove(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Affirms if the given resource represents a classpath.
|
||||
*/
|
||||
private boolean isClasspath(IResourceDelta resource) {
|
||||
IPackageFragmentRoot path = (IPackageFragmentRoot)resource.getAdapter(IPackageFragmentRoot.class);
|
||||
return path != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note that if full/verbose logging is enabled, which writes to that Error
|
||||
* Log view, then something in Eclipse (3.4 at least) goes wrong with the
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.core.runtime.CoreException;
|
|||
*
|
||||
* @author Eclipse PDE Example Wizard! ;-)
|
||||
* @author Michael Vorburger (MVO)
|
||||
* @author Pinaki Poddar
|
||||
*/
|
||||
public class OpenJPANature implements IProjectNature {
|
||||
|
||||
|
@ -68,8 +69,7 @@ public class OpenJPANature implements IProjectNature {
|
|||
if (commands[i].getBuilderName().equals(OpenJPAEnhancerBuilder.BUILDER_ID)) {
|
||||
ICommand[] newCommands = new ICommand[commands.length - 1];
|
||||
System.arraycopy(commands, 0, newCommands, 0, i);
|
||||
System.arraycopy(commands, i + 1, newCommands, i,
|
||||
commands.length - i - 1);
|
||||
System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
|
||||
description.setBuildSpec(newCommands);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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.apache.openjpa.eclipse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import org.apache.openjpa.eclipse.util.ClassLoaderFromIProjectHelper;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.FileLocator;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
|
||||
import org.eclipse.jface.operation.IRunnableWithProgress;
|
||||
import org.eclipse.osgi.util.ManifestElement;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleException;
|
||||
import org.osgi.framework.Constants;
|
||||
|
||||
|
||||
/**
|
||||
* Locates the required runtime class libraries for OpenJPA by looking up the Bundle manifest.
|
||||
* These libraries are embedded in the plugin jar and hence can not directly be used as
|
||||
* classpath entry for a user project. Hence these runtime libaries are read from the
|
||||
* plugin jar and copied into the user project.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class PluginLibrary {
|
||||
/**
|
||||
* This identifier must match the <code>Bundle.Symbolic-Name</code> of the root manifest.
|
||||
*/
|
||||
public static final String BUNDLE_ID = "org.apache.openjpa";
|
||||
|
||||
/**
|
||||
* Map of library key to marker class name. Used to determine if a specific library
|
||||
* is visible to the user's project's classloader.
|
||||
*/
|
||||
private static final Map<String,String> probes = new HashMap<String, String>();
|
||||
static {
|
||||
probes.put("commons-collections", "org.apache.commons.collections.ArrayStack");
|
||||
probes.put("commons-lang", "org.apache.commons.lang.ObjectUtils");
|
||||
probes.put("geronimo-jms", "javax.jms.Connection");
|
||||
probes.put("geronimo-jpa", "javax.persistence.Entity");
|
||||
probes.put("geronimo-jta", "javax.transaction.Transaction");
|
||||
probes.put("openjpa", "org.apache.openjpa.conf.OpenJPAVersion");
|
||||
probes.put("serp", "serp.bytecode.BCClass");
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
Bundle bundle = Platform.getBundle(BUNDLE_ID);
|
||||
Object desc = bundle.getHeaders().get(Constants.BUNDLE_DESCRIPTION);
|
||||
return desc == null ? "OpenJPA Eclipse Plugin Bundle" : desc.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given bundle manifest for the names of libraries required for
|
||||
* OpenJPA runtime.
|
||||
*/
|
||||
private List<String> getRuntimeLibraries(Bundle bundle) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
try {
|
||||
String cpEntries = (String) bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
|
||||
if (cpEntries == null)
|
||||
cpEntries = ".";
|
||||
ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, cpEntries);
|
||||
for (int i = 0; i < elements.length; ++i) {
|
||||
ManifestElement element = elements[i];
|
||||
String value = element.getValue();
|
||||
result.add(value);
|
||||
}
|
||||
} catch (BundleException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the runtime libraries required for this bundle to the given project.
|
||||
*
|
||||
* @param list of patterns that matches an actual library. null implies all runtime libraries.
|
||||
* @param copy if true then the libraries are copied to the given project directory.
|
||||
*/
|
||||
public IClasspathEntry[] getLibraryClasspaths(IProject project, List<String> libs, boolean copy) throws CoreException {
|
||||
if (libs != null && libs.isEmpty())
|
||||
return new IClasspathEntry[0];
|
||||
Bundle bundle = Platform.getBundle(BUNDLE_ID);
|
||||
List<String> libraries = getRuntimeLibraries(bundle);
|
||||
List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
|
||||
ProgressMonitorDialog progress = null;
|
||||
for (String lib : libraries) {
|
||||
try {
|
||||
if (".".equals(lib))
|
||||
continue;
|
||||
URL url = bundle.getEntry(lib);
|
||||
url = FileLocator.resolve(url);
|
||||
String urlString = url.getFile();
|
||||
if (!urlString.endsWith(".jar") || !matchesPattern(urlString, libs))
|
||||
continue;
|
||||
String libName = urlString.substring(urlString.indexOf('!')+1);
|
||||
IFile iFile = project.getFile(libName);
|
||||
if (iFile == null) {
|
||||
continue;
|
||||
}
|
||||
IPath outPath = iFile.getRawLocation();
|
||||
File outFile = outPath.toFile();
|
||||
if (!outFile.getParentFile().exists() && copy) {
|
||||
outFile.getParentFile().mkdirs();
|
||||
}
|
||||
if (!outFile.exists() && copy) {
|
||||
outFile.createNewFile();
|
||||
}
|
||||
if (copy) {
|
||||
boolean firstTask = progress == null;
|
||||
if (progress == null) {
|
||||
progress = new ProgressMonitorDialog(Activator.getShell());
|
||||
}
|
||||
if (firstTask) {
|
||||
int nTask = libs == null ? libraries.size() : libs.size();
|
||||
progress.run(true, false, new JarCopier(url.openStream(),outFile, true, nTask));
|
||||
} else {
|
||||
progress.run(true, false, new JarCopier(url.openStream(),outFile));
|
||||
}
|
||||
}
|
||||
IClasspathEntry classpath = JavaCore.newLibraryEntry(outPath, null, null);
|
||||
entries.add(classpath);
|
||||
} catch (Exception e) {
|
||||
Activator.log(e);
|
||||
} finally {
|
||||
if (progress != null) {
|
||||
progress.getProgressMonitor().done();
|
||||
}
|
||||
}
|
||||
}
|
||||
return entries.toArray(new IClasspathEntry[entries.size()]);
|
||||
}
|
||||
|
||||
void copyJar(JarInputStream jar, JarOutputStream out) throws IOException {
|
||||
if (jar == null || out == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
JarEntry entry = null;
|
||||
while ((entry = jar.getNextJarEntry()) != null) {
|
||||
out.putNextEntry(entry);
|
||||
int b = -1;
|
||||
while ((b = jar.read()) != -1) {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
out.closeEntry();
|
||||
} finally {
|
||||
out.finish();
|
||||
out.flush();
|
||||
out.close();
|
||||
jar.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the libraries that are required but missing from the given project's classpath.
|
||||
* @param project
|
||||
* @return empty list if no required libraries are missing.
|
||||
*/
|
||||
public List<String> findMissingLibrary(IProject project) throws CoreException {
|
||||
List<String> missing = new ArrayList<String>();
|
||||
ClassLoader projectClassLoader = ClassLoaderFromIProjectHelper.createClassLoader(project);
|
||||
for (Map.Entry<String, String> e : probes.entrySet()) {
|
||||
try {
|
||||
Class.forName(e.getValue(), false, projectClassLoader);
|
||||
} catch (Exception cnf) {
|
||||
missing.add(e.getKey());
|
||||
}
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affirms if any of the given pattern is present in the given full name.
|
||||
* @return
|
||||
*/
|
||||
private boolean matchesPattern(String fullName, List<String> patterns) {
|
||||
if (patterns == null)
|
||||
return true;
|
||||
for (String pattern : patterns) {
|
||||
if (fullName.indexOf(pattern) != -1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class JarCopier implements IRunnableWithProgress {
|
||||
final JarInputStream in;
|
||||
final JarOutputStream out;
|
||||
final boolean beginTask;
|
||||
final int size;
|
||||
final String message;
|
||||
public JarCopier(InputStream jar, File outFile) throws IOException {
|
||||
this(jar, outFile, false, 0);
|
||||
}
|
||||
|
||||
public JarCopier(InputStream jar, File outFile, boolean begin, int size) throws IOException {
|
||||
super();
|
||||
this.in = new JarInputStream(jar);
|
||||
this.out = new JarOutputStream(new FileOutputStream(outFile));
|
||||
this.beginTask = begin;
|
||||
this.size = size;
|
||||
this.message = outFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
|
||||
if (in == null || out == null)
|
||||
return;
|
||||
if (beginTask)
|
||||
monitor.beginTask("Copying OpenJPA runtime libraries to user projects", size);
|
||||
monitor.subTask(message);
|
||||
try {
|
||||
try {
|
||||
JarEntry entry = null;
|
||||
while ((entry = in.getNextJarEntry()) != null) {
|
||||
out.putNextEntry(entry);
|
||||
int b = -1;
|
||||
while ((b = in.read()) != -1) {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
out.closeEntry();
|
||||
} finally {
|
||||
out.finish();
|
||||
out.flush();
|
||||
out.close();
|
||||
in.close();
|
||||
monitor.worked(1);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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.apache.openjpa.eclipse;
|
||||
|
||||
import org.eclipse.core.runtime.QualifiedName;
|
||||
|
||||
/**
|
||||
* Enumerates persistent properties of the project.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class PluginProperty {
|
||||
/**
|
||||
* Is the project using the plugin's captive version of OpenJPA runtime libraries?
|
||||
*
|
||||
* Allowed values: "true" or "false"
|
||||
*/
|
||||
public static final QualifiedName USING_CAPTIVE_LIBS = qname("openjpa.usingCaptiveLibs");
|
||||
|
||||
/**
|
||||
* Does the project requires plugin's captive version of OpenJPA runtime libraries to be added?
|
||||
*
|
||||
* Allowed values: "true" or "false"
|
||||
*/
|
||||
public static final QualifiedName REQUIRES_CAPTIVE_LIBS = qname("openjpa.requiresCaptiveLibs");
|
||||
|
||||
/**
|
||||
* Does enhancer add a no-argument constructor for a persistent entity?
|
||||
*
|
||||
* Allowed values: "true" or "false"
|
||||
*/
|
||||
public static final QualifiedName ADD_CONSTRUCTOR = qname("enhancer.addConstructor");
|
||||
/**
|
||||
* Does enhancer enforce property based access restrictions?
|
||||
*
|
||||
* Allowed values: "true" or "false"
|
||||
*/
|
||||
public static final QualifiedName ENFORCE_PROP = qname("enhancer.enforceProperty");
|
||||
|
||||
/**
|
||||
* The output directory for enhanced classes.
|
||||
*
|
||||
* Allowed values: a directory
|
||||
*/
|
||||
public static final QualifiedName ENHANCER_OUTPUT = qname("enhancer.output.dir");
|
||||
|
||||
private static QualifiedName qname(String s) {
|
||||
return new QualifiedName(Activator.PLUGIN_ID, s);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,15 +16,28 @@
|
|||
|
||||
package org.apache.openjpa.eclipse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.openjpa.eclipse.ui.AddNatureDialog;
|
||||
import org.apache.openjpa.eclipse.ui.ProjectDecorator;
|
||||
import org.apache.openjpa.eclipse.ui.RemoveNatureDialog;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IProjectDescription;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jface.action.IAction;
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.IObjectActionDelegate;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
|
||||
|
@ -33,6 +46,7 @@ import org.eclipse.ui.IWorkbenchPart;
|
|||
*
|
||||
* @author Eclipse PDE Example Wizard! ;-)
|
||||
* @author Michael Vorburger (MVO)
|
||||
* @author Pinaki Poddar
|
||||
*/
|
||||
public class ToggleNatureAction implements IObjectActionDelegate {
|
||||
|
||||
|
@ -46,15 +60,13 @@ public class ToggleNatureAction implements IObjectActionDelegate {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void run(IAction action) {
|
||||
if (selection instanceof IStructuredSelection) {
|
||||
for (Iterator it = ((IStructuredSelection) selection).iterator(); it
|
||||
.hasNext();) {
|
||||
for (Iterator it = ((IStructuredSelection) selection).iterator(); it.hasNext();) {
|
||||
Object element = it.next();
|
||||
IProject project = null;
|
||||
if (element instanceof IProject) {
|
||||
project = (IProject) element;
|
||||
} else if (element instanceof IAdaptable) {
|
||||
project = (IProject) ((IAdaptable) element)
|
||||
.getAdapter(IProject.class);
|
||||
project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
|
||||
}
|
||||
if (project != null) {
|
||||
toggleNature(project);
|
||||
|
@ -88,31 +100,170 @@ public class ToggleNatureAction implements IObjectActionDelegate {
|
|||
* @param project
|
||||
* to have sample nature added or removed
|
||||
*/
|
||||
private void toggleNature(IProject project) {
|
||||
try {
|
||||
IProjectDescription description = project.getDescription();
|
||||
String[] natures = description.getNatureIds();
|
||||
/**
|
||||
* Toggles the nature of the given project.
|
||||
*
|
||||
*/
|
||||
private void toggleNature(IProject project) {
|
||||
try {
|
||||
int natureIndex = getNatureIndex(project, OpenJPANature.NATURE_ID);
|
||||
if (natureIndex != -1) {
|
||||
removeNature(project, natureIndex);
|
||||
} else {
|
||||
addNature(project, OpenJPANature.NATURE_ID);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Activator.log(e);
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < natures.length; ++i) {
|
||||
if (OpenJPANature.NATURE_ID.equals(natures[i])) {
|
||||
// Remove the nature
|
||||
String[] newNatures = new String[natures.length - 1];
|
||||
System.arraycopy(natures, 0, newNatures, 0, i);
|
||||
System.arraycopy(natures, i + 1, newNatures, i,
|
||||
natures.length - i - 1);
|
||||
description.setNatureIds(newNatures);
|
||||
project.setDescription(description, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Adds given nature to the project.
|
||||
* Adding a nature also involves finding out which require runtime libraries, if any, are missing
|
||||
* from the given project and then copying those libraries from the bundle to the project.
|
||||
* @param project
|
||||
* @param natureId
|
||||
* @return
|
||||
* @throws CoreException
|
||||
*/
|
||||
private boolean addNature(IProject project, String natureId) throws CoreException {
|
||||
Activator.log("Adding nature " + natureId + " to project " + project.getName());
|
||||
PluginLibrary bundle = new PluginLibrary();
|
||||
List<String> missingLibraries = bundle.findMissingLibrary(project);
|
||||
Shell shell = Activator.getShell();
|
||||
AddNatureDialog dialog = new AddNatureDialog(shell, project,
|
||||
"Enable OpenJPA",
|
||||
"OpenJPA Plugin",
|
||||
"Enhances bytecode of persistent entities as you compile",
|
||||
missingLibraries);
|
||||
dialog.open();
|
||||
if (dialog.getReturnCode() != Window.OK) {
|
||||
return false;
|
||||
}
|
||||
IProjectDescription description = project.getDescription();
|
||||
String[] natures = description.getNatureIds();
|
||||
String[] newNatures = new String[natures.length + 1];
|
||||
System.arraycopy(natures, 0, newNatures, 0, natures.length);
|
||||
newNatures[natures.length] = OpenJPANature.NATURE_ID;
|
||||
description.setNatureIds(newNatures);
|
||||
project.setDescription(description, null);
|
||||
|
||||
// Add the nature
|
||||
String[] newNatures = new String[natures.length + 1];
|
||||
System.arraycopy(natures, 0, newNatures, 0, natures.length);
|
||||
newNatures[natures.length] = OpenJPANature.NATURE_ID;
|
||||
description.setNatureIds(newNatures);
|
||||
project.setDescription(description, null);
|
||||
} catch (CoreException e) {
|
||||
}
|
||||
}
|
||||
if ("true".equals(project.getPersistentProperty(PluginProperty.REQUIRES_CAPTIVE_LIBS))) {
|
||||
IClasspathEntry[] librariesToAdd = bundle.getLibraryClasspaths(project, missingLibraries, true);
|
||||
addClasspath(project, librariesToAdd);
|
||||
} else if (!missingLibraries.isEmpty()) {
|
||||
MessageDialog.openWarning(Activator.getShell(), "Missing Libraries",
|
||||
"This project does not have the required runtime libraries. You must add them manually");
|
||||
}
|
||||
fireLabelEvent(project);
|
||||
Activator.log("Adding nature " + natureId + " to project " + project.getName() + " done...");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the captive runtime libraries of the bundle to the classpath of the given project.
|
||||
*/
|
||||
private void addClasspath(IProject project, IClasspathEntry[] libs) throws CoreException {
|
||||
if (libs.length == 0)
|
||||
return;
|
||||
IJavaProject javaProject = JavaCore.create(project);
|
||||
IClasspathEntry[] projectClasspaths = javaProject.getRawClasspath();
|
||||
|
||||
IClasspathEntry[] newClasspaths = new IClasspathEntry[projectClasspaths.length + libs.length];
|
||||
System.arraycopy(libs, 0, newClasspaths, 0, libs.length);
|
||||
System.arraycopy(projectClasspaths, 0, newClasspaths, libs.length, projectClasspaths.length);
|
||||
javaProject.setRawClasspath(newClasspaths, null);
|
||||
|
||||
project.setPersistentProperty(PluginProperty.USING_CAPTIVE_LIBS, ""+true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the nature from the project. Removes captive OpenJPA libraries from the project's classpath,
|
||||
* if it has been added.
|
||||
*/
|
||||
private boolean removeNature(IProject project, int natureIndex) throws CoreException {
|
||||
Shell shell = Activator.getShell();
|
||||
RemoveNatureDialog dialog = new RemoveNatureDialog(shell, project,
|
||||
"Disable OpenJPA",
|
||||
"OpenJPA Plugin",
|
||||
"Enhances bytecode of persistent entities as you compile");
|
||||
dialog.open();
|
||||
if (dialog.getReturnCode() != Window.OK) {
|
||||
return false;
|
||||
}
|
||||
IProjectDescription description = project.getDescription();
|
||||
String[] natures = description.getNatureIds();
|
||||
Activator.log(this + ".removeNature(" + OpenJPANature.NATURE_ID + ")");
|
||||
String[] newNatures = new String[natures.length - 1];
|
||||
System.arraycopy(natures, 0, newNatures, 0, natureIndex);
|
||||
System.arraycopy(natures, natureIndex + 1, newNatures, natureIndex, natures.length - natureIndex - 1);
|
||||
description.setNatureIds(newNatures);
|
||||
project.setDescription(description, null);
|
||||
|
||||
removeClasspath(project);
|
||||
fireLabelEvent(project);
|
||||
|
||||
Activator.log(this + ".removeNature()...done");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the given nature in the given project.
|
||||
* @param project
|
||||
* @param natureId
|
||||
* @return -1 if the nature is not present.
|
||||
* @throws CoreException
|
||||
*/
|
||||
private int getNatureIndex(IProject project, String natureId) throws CoreException {
|
||||
IProjectDescription description = project.getDescription();
|
||||
String[] natures = description.getNatureIds();
|
||||
for (int i = 0; i < natures.length; ++i) {
|
||||
if (OpenJPANature.NATURE_ID.equals(natures[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// remove classpath entries
|
||||
private void removeClasspath(IProject project) throws CoreException {
|
||||
if ("false".equalsIgnoreCase(project.getPersistentProperty(PluginProperty.USING_CAPTIVE_LIBS))) {
|
||||
return;
|
||||
}
|
||||
IJavaProject javaProject = JavaCore.create(project);
|
||||
IClasspathEntry[] projectClasspaths = javaProject.getRawClasspath();
|
||||
|
||||
PluginLibrary cpc = new PluginLibrary();
|
||||
IClasspathEntry[] cpsOpenJPA = cpc.getLibraryClasspaths(project, null, false);
|
||||
List<IClasspathEntry> cpsModified = new ArrayList<IClasspathEntry>();
|
||||
cpsModified.addAll(Arrays.asList(projectClasspaths));
|
||||
cpsModified.removeAll(Arrays.asList(cpsOpenJPA));
|
||||
javaProject.setRawClasspath(cpsModified.toArray(new IClasspathEntry[cpsModified.size()]), null);
|
||||
|
||||
project.setPersistentProperty(PluginProperty.USING_CAPTIVE_LIBS, ""+false);
|
||||
}
|
||||
|
||||
boolean contains(IClasspathEntry[] list, IClasspathEntry key) {
|
||||
for (IClasspathEntry cp : list) {
|
||||
if (cp.equals(key))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an event to redraw the label for the given project element.
|
||||
*/
|
||||
private void fireLabelEvent(final IProject project) {
|
||||
Activator.getDisplay().asyncExec(new Runnable() {
|
||||
public void run() {
|
||||
ProjectDecorator labeler = Activator.getLabelProvider();
|
||||
if (labeler == null)
|
||||
return;
|
||||
LabelProviderChangedEvent event = new LabelProviderChangedEvent(labeler, project);
|
||||
labeler.fireLabelProviderChanged(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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.apache.openjpa.eclipse.ui;
|
||||
|
||||
import org.apache.openjpa.eclipse.Activator;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.dialogs.TitleAreaDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
public abstract class AbstractDialog extends TitleAreaDialog {
|
||||
protected final IProject project;
|
||||
protected final String header;
|
||||
protected final String title;
|
||||
protected final String message;
|
||||
|
||||
public static Image logo;
|
||||
static {
|
||||
try {
|
||||
logo = Activator.getImageDescriptor("icons/openjpa-logo-small.png").createImage();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractDialog(Shell parentShell, IProject project, String header, String title, String message) {
|
||||
super(parentShell);
|
||||
this.project = project;
|
||||
this.header = header;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.setBlockOnOpen(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the dialog's contents
|
||||
*
|
||||
* @param parent the parent composite
|
||||
* @return Control
|
||||
*/
|
||||
protected Control createContents(Composite parent) {
|
||||
Control contents = super.createContents(parent);
|
||||
|
||||
this.setTitle(title);
|
||||
this.setMessage(message);
|
||||
this.setTitleImage(logo);
|
||||
getShell().setText(header);
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the dialog's content area
|
||||
*
|
||||
*/
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
Composite composite = new Composite(parent, SWT.NONE);
|
||||
GridLayout layout = new GridLayout();
|
||||
layout.marginHeight = 0;
|
||||
layout.marginWidth = 0;
|
||||
layout.verticalSpacing = 10;
|
||||
layout.horizontalSpacing = 10;
|
||||
layout.marginLeft = 10;
|
||||
layout.marginRight = 10;
|
||||
composite.setLayout(layout);
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
composite.setLayoutData(gridData);
|
||||
composite.setFont(parent.getFont());
|
||||
// Build the separator line
|
||||
Label titleBarSeparator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR);
|
||||
titleBarSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the buttons for the button bar.
|
||||
*
|
||||
* @param parent the parent composite
|
||||
*/
|
||||
protected void createButtonsForButtonBar(Composite parent) {
|
||||
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
|
||||
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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.apache.openjpa.eclipse.ui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.openjpa.eclipse.PluginProperty;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.QualifiedName;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.SelectionListener;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
/**
|
||||
* A dialog to inform that bundle runtime libraries will be added to the classpath of
|
||||
* a project.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class AddNatureDialog extends AbstractDialog {
|
||||
|
||||
private final List<String> requiredLibs;
|
||||
private Button addLibrary;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Display d = Display.getDefault();//PlatformUI.getWorkbench().getDisplay();
|
||||
Shell shell = new Shell(d);
|
||||
AddNatureDialog dialog = new AddNatureDialog(shell, null, "Test Header", "Test Title", "Test Message",
|
||||
new ArrayList<String>());
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
public AddNatureDialog(Shell parentShell, IProject project, String header, String title, String message,
|
||||
List<String> libariesToBeAdded) {
|
||||
super(parentShell, project, header, title, message);
|
||||
if (libariesToBeAdded == null) {
|
||||
requiredLibs = Collections.emptyList();
|
||||
} else {
|
||||
requiredLibs = libariesToBeAdded;
|
||||
}
|
||||
try {
|
||||
project.setPersistentProperty(PluginProperty.REQUIRES_CAPTIVE_LIBS, ""+!requiredLibs.isEmpty());
|
||||
} catch (CoreException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the dialog's content area.
|
||||
*
|
||||
*/
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
Composite composite = (Composite)super.createDialogArea(parent);
|
||||
|
||||
boolean requiresCaptiveLibs = !requiredLibs.isEmpty();
|
||||
String message = requiresCaptiveLibs
|
||||
? "Following libraries are missing from the project's classpath. \r\n" +
|
||||
"The plugin's captive version of these libraries will be added to the project's classpath.\r\n" +
|
||||
"If you want to add the libraries manually later, please uncheck the box."
|
||||
: "Required libraries are already available to the project's classpath";
|
||||
|
||||
addLibrary = createCheckBox(composite, message, PluginProperty.REQUIRES_CAPTIVE_LIBS);
|
||||
addLibrary.setSelection(requiresCaptiveLibs);
|
||||
addLibrary.setEnabled(requiresCaptiveLibs);
|
||||
if (requiresCaptiveLibs) {
|
||||
org.eclipse.swt.widgets.List libList = new
|
||||
org.eclipse.swt.widgets.List(composite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
|
||||
for (String lib : requiredLibs)
|
||||
libList.add(lib);
|
||||
libList.setEnabled(false);
|
||||
}
|
||||
final Group enhanceOptions = new Group(composite, SWT.NONE);
|
||||
enhanceOptions.setText("Bytecode Enhancement Options");
|
||||
GridLayout layout = new GridLayout();
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
|
||||
layout.marginTop = 10;
|
||||
layout.marginBottom = 10;
|
||||
enhanceOptions.setLayout(layout);
|
||||
enhanceOptions.setLayoutData(gridData);
|
||||
|
||||
Button overwrite = createCheckBox(enhanceOptions, "Overwrite *.class files");
|
||||
overwrite.setSelection(true);
|
||||
overwrite.setGrayed(true);
|
||||
overwrite.setEnabled(false);
|
||||
|
||||
Button output = createCheckBox(enhanceOptions, "Write enhanced classes", null);
|
||||
output.setSelection(true);
|
||||
output.setGrayed(true);
|
||||
output.setEnabled(false);
|
||||
|
||||
createCheckBox(enhanceOptions, "Add no-arg constructor to persistent entity", PluginProperty.ADD_CONSTRUCTOR);
|
||||
createCheckBox(enhanceOptions, "Enforce Property Restriction", PluginProperty.ENFORCE_PROP);
|
||||
|
||||
new Label(parent, SWT.NONE); // empty space
|
||||
Label endBar = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
|
||||
endBar.setLayoutData(new GridData(GridData.GRAB_VERTICAL|GridData.FILL_HORIZONTAL));
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
public boolean getAddLibrary() {
|
||||
return addLibrary.getSelection();
|
||||
}
|
||||
|
||||
Button createCheckBox(Composite parent, String text) {
|
||||
return createCheckBox(parent, text, null);
|
||||
}
|
||||
|
||||
Button createCheckBox(Composite parent, String text, QualifiedName prop) {
|
||||
Button b = new Button(parent, SWT.CHECK);
|
||||
b.setText(text);
|
||||
GridData gridData = new GridData(GridData.FILL, GridData.CENTER, true, false);
|
||||
b.setLayoutData(gridData);
|
||||
if (prop != null) {
|
||||
b.addSelectionListener(new BooleanPropertyRegister(b, prop));
|
||||
try {
|
||||
boolean selected = "true".equals(project.getPersistentProperty(prop));
|
||||
b.setSelection(selected);
|
||||
} catch (CoreException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks the given boolean property of a project by selection state of the given button.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
private class BooleanPropertyRegister implements SelectionListener {
|
||||
private Button button;
|
||||
private QualifiedName property;
|
||||
|
||||
/**
|
||||
* Sets the state of the given button according to the boolean value of the given property.
|
||||
* @param b the button to attach to the given property.
|
||||
* @param p the property to track
|
||||
*/
|
||||
public BooleanPropertyRegister(Button b, QualifiedName p) {
|
||||
button = b;
|
||||
property = p;
|
||||
if (property != null) {
|
||||
}
|
||||
}
|
||||
|
||||
public void widgetDefaultSelected(SelectionEvent e) {
|
||||
}
|
||||
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
if (property != null) {
|
||||
try {
|
||||
project.setPersistentProperty(property, ""+button.getSelection());
|
||||
} catch (CoreException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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.apache.openjpa.eclipse.ui;
|
||||
|
||||
import org.apache.openjpa.eclipse.Activator;
|
||||
import org.apache.openjpa.eclipse.OpenJPANature;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.viewers.IDecoration;
|
||||
import org.eclipse.jface.viewers.ILabelProviderListener;
|
||||
import org.eclipse.jface.viewers.ILightweightLabelDecorator;
|
||||
import org.eclipse.jface.viewers.LabelProvider;
|
||||
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
|
||||
|
||||
/**
|
||||
* Decorates the project root node with an image if OpenJPA nature is enabled for the project.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class ProjectDecorator extends LabelProvider implements ILightweightLabelDecorator, ILabelProviderListener {
|
||||
public static final String DECORATOR_ID = "org.apache.openjpa.eclipse.Decorator";
|
||||
public static final ImageDescriptor decor = Activator.getImageDescriptor("icons/apache-feather-small.jpg");
|
||||
|
||||
public ProjectDecorator() {
|
||||
addListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate the project root if it has the OpenJPA nature.
|
||||
*/
|
||||
public void decorate(Object element, IDecoration decoration) {
|
||||
if (!(element instanceof IProject)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (((IProject)element).hasNature(OpenJPANature.NATURE_ID)) {
|
||||
decoration.addOverlay(decor);
|
||||
} else {
|
||||
decoration.addOverlay(null);
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
removeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the label will be affected by the change in the given property of the given element.
|
||||
* Always returns false.
|
||||
*/
|
||||
public boolean isLabelProperty(Object element, String property) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void fireLabelProviderChanged(LabelProviderChangedEvent e) {
|
||||
super.fireLabelProviderChanged(e);
|
||||
}
|
||||
|
||||
public void labelProviderChanged(LabelProviderChangedEvent event) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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.apache.openjpa.eclipse.ui;
|
||||
|
||||
import org.apache.openjpa.eclipse.PluginProperty;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
/**
|
||||
* A dialog to confirm removing the nature from user project.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class RemoveNatureDialog extends AbstractDialog {
|
||||
|
||||
public RemoveNatureDialog(Shell parentShell, IProject project, String header, String title, String message) {
|
||||
super(parentShell, project, header, title, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the dialog's content area.
|
||||
*
|
||||
*/
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
Composite composite = (Composite)super.createDialogArea(parent);
|
||||
boolean warn = false;
|
||||
try {
|
||||
warn = "true".equalsIgnoreCase(project.getPersistentProperty(PluginProperty.USING_CAPTIVE_LIBS));
|
||||
} catch (CoreException e) {
|
||||
}
|
||||
String message = warn
|
||||
? "Disabling OpenJPA will remove runtime libraries added to " + project.getName() + ".\r\n" +
|
||||
"This project may not build after removing these libraries.\r\n" +
|
||||
"Are you sure you want to remove OpenJPA nature from " + project.getName() + "?"
|
||||
: "Remove OpenJPA nature from" + project.getName() + "?";
|
||||
new Label(composite, SWT.NONE).setText(message);
|
||||
|
||||
Label endBar = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
|
||||
endBar.setLayoutData(new GridData(GridData.GRAB_VERTICAL|GridData.FILL_HORIZONTAL));
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Display d = Display.getDefault();//PlatformUI.getWorkbench().getDisplay();
|
||||
Shell shell = new Shell(d);
|
||||
RemoveNatureDialog dialog = new RemoveNatureDialog(shell, null, "Test Header", "Test Title", "Test Message");
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -20,7 +20,6 @@ import java.net.MalformedURLException;
|
|||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
|
||||
import org.apache.openjpa.eclipse.Activator;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
@ -37,18 +36,31 @@ import org.eclipse.jdt.launching.JavaRuntime;
|
|||
* @author Michael Vorburger
|
||||
*/
|
||||
public class ClassLoaderFromIProjectHelper {
|
||||
private static final char BACKSLASH = '\\';
|
||||
private static final char FORWARDSLASH = '/';
|
||||
private static final String PROTOCOL_FILE = "file:///";
|
||||
private static final String JAR_EXTENSION = ".jar";
|
||||
private static final String DIRECTORY_MARKER = "/";
|
||||
|
||||
/**
|
||||
* Creates a classloader for the given Eclipse Project.
|
||||
*
|
||||
* @param project a Eclipse Java Project
|
||||
* @return a URLClassLoader with the configured classpath of the given project
|
||||
* @throws CoreException
|
||||
*/
|
||||
public static ClassLoader createClassLoader(IProject project) throws CoreException {
|
||||
IJavaProject javaProject = JavaCore.create(project);
|
||||
String[] classPath = JavaRuntime.computeDefaultRuntimeClassPath(javaProject);
|
||||
URL[] urls = new URL[classPath.length];
|
||||
for(int i=0;i<classPath.length;i++) {
|
||||
for(int i=0; i < classPath.length; i++) {
|
||||
try {
|
||||
String urlString = "file:///" + classPath[i].replace('\\', '/');
|
||||
String urlString = PROTOCOL_FILE + classPath[i].replace(BACKSLASH, FORWARDSLASH);
|
||||
|
||||
// make sure that directory URLs end with a slash as they are otherwise not
|
||||
// treated as directories but as libraries by the URLClassLoader
|
||||
if(!classPath[i].endsWith(".jar") && !classPath[i].endsWith("/")) urlString += "/";
|
||||
if(!classPath[i].endsWith(JAR_EXTENSION) && !classPath[i].endsWith(DIRECTORY_MARKER))
|
||||
urlString += DIRECTORY_MARKER;
|
||||
urls[i] = new URL(urlString);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
|
||||
|
@ -57,4 +69,18 @@ public class ClassLoaderFromIProjectHelper {
|
|||
}
|
||||
return URLClassLoader.newInstance(urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class of the given name by loading it using the given project's classpath.
|
||||
*
|
||||
* @return null if the given class can not be loaded.
|
||||
*/
|
||||
public static Class<?> findClass(String className, IProject project) {
|
||||
try {
|
||||
return Class.forName(className, false, createClassLoader(project));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ import serp.bytecode.BCClass;
|
|||
import serp.bytecode.Project;
|
||||
|
||||
/**
|
||||
* OpenJPA Enhancer helper, for efficient invocation from an Eclipse builder.
|
||||
* OpenJPA Enhancer for efficient invocation from an Eclipse builder.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
* @author Michael Vorburger (refactoring and extensions)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 794 B |
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
|
@ -67,4 +67,5 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
Loading…
Reference in New Issue