| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.j2ee.weblogic9.deploy; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.FilenameFilter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.jar.Attributes.Name; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| import java.util.jar.JarInputStream; |
| import java.util.jar.JarOutputStream; |
| import java.util.jar.Manifest; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.regex.Pattern; |
| import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException; |
| import org.netbeans.modules.j2ee.core.api.support.progress.ProgressSupport; |
| import org.netbeans.modules.j2ee.core.api.support.progress.ProgressSupport.Context; |
| import org.netbeans.modules.j2ee.deployment.common.api.Version; |
| import org.netbeans.modules.j2ee.deployment.devmodules.api.Deployment; |
| import org.netbeans.modules.j2ee.deployment.plugins.api.InstanceProperties; |
| import org.netbeans.modules.j2ee.weblogic9.WLDeploymentFactory; |
| import org.netbeans.modules.j2ee.weblogic9.WLPluginProperties; |
| import org.netbeans.modules.j2ee.weblogic9.WLProductProperties; |
| import org.netbeans.modules.j2ee.weblogic9.j2ee.WLJ2eePlatformFactory; |
| import org.netbeans.modules.weblogic.common.api.WebLogicLayout; |
| import org.netbeans.spi.project.libraries.LibraryImplementation; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.util.Exceptions; |
| import org.openide.util.NbBundle; |
| |
| /** |
| * |
| * @author Petr Hejl |
| */ |
| public final class WLJpa2SwitchSupport { |
| |
| private static final Version SWITCH_SUPPORTED_VERSION_MIN = |
| Version.fromJsr277NotationWithFallback("10.3.4"); // NOI18N |
| |
| private static final String OEPE_CONTRIBUTIONS_JAR = "oepe-contributions.jar"; // NO18N |
| |
| private static final Pattern JPA_JAR_1_PATTERN = Pattern.compile("^.*javax\\.persistence.*(_2-\\d+(-\\d+)?)\\.jar$"); // NO18N |
| |
| private static final String JPA_JAR1_FALLBACK = "javax.persistence_1.0.0.0_2-0-0.jar"; // NOI18N |
| |
| private static final Pattern JPA_JAR_2_PATTERN = Pattern.compile("^.*com\\.oracle\\.jpa2support.*\\.jar$"); // NO18N |
| |
| private static final String JPA_JAR2_FALLBACK = "com.oracle.jpa2support_1.0.0.0_2-0.jar"; // NOI18N |
| |
| private static final Logger LOGGER = Logger.getLogger(WLJpa2SwitchSupport.class.getName()); |
| |
| private final File serverRoot; |
| |
| private final WLDeploymentManager dm; |
| |
| /** GuardedBy("this")*/ |
| private Version serverVersion; |
| |
| public WLJpa2SwitchSupport(File serverRoot) { |
| this.dm = null; |
| this.serverRoot = serverRoot; |
| } |
| |
| public WLJpa2SwitchSupport(WLDeploymentManager dm) { |
| this.dm = dm; |
| this.serverRoot = WLPluginProperties.getServerRoot(dm, true); |
| } |
| |
| public boolean isSwitchSupported() { |
| Version version = null; |
| synchronized (this) { |
| if (serverVersion != null) { |
| version = serverVersion; |
| } else { |
| if (dm != null) { |
| version = dm.getServerVersion(); |
| } else { |
| version = WLPluginProperties.getServerVersion(serverRoot); |
| } |
| serverVersion = version; |
| } |
| } |
| return version != null && version.isAboveOrEqual(SWITCH_SUPPORTED_VERSION_MIN) |
| && SWITCH_SUPPORTED_VERSION_MIN.getMajor().equals(version.getMajor()) |
| && SWITCH_SUPPORTED_VERSION_MIN.getMinor().equals(version.getMinor()); |
| } |
| |
| public void enable() { |
| List<ProgressSupport.Action> actions = new ArrayList<ProgressSupport.Action>(); |
| actions.add(new ProgressSupport.BackgroundAction() { |
| |
| @Override |
| protected void run(Context actionContext) { |
| actionContext.progress(NbBundle.getMessage(WLJpa2SwitchSupport.class, "MSG_Enabling_JPA2")); |
| doEnable(); |
| } |
| }); |
| ProgressSupport.invoke(actions); |
| } |
| |
| public void disable() { |
| List<ProgressSupport.Action> actions = new ArrayList<ProgressSupport.Action>(); |
| actions.add(new ProgressSupport.BackgroundAction() { |
| |
| @Override |
| protected void run(Context actionContext) { |
| actionContext.progress(NbBundle.getMessage(WLJpa2SwitchSupport.class, "MSG_Disabling_JPA2")); |
| doDisable(); |
| } |
| }); |
| ProgressSupport.invoke(actions); |
| } |
| |
| private void doEnable() { |
| if (!isSwitchSupported()) { |
| throw new IllegalStateException("JPA2 switching is not supported for WebLogic " + serverRoot); |
| } |
| |
| try { |
| File libDir = WLPluginProperties.getServerLibDirectory(serverRoot); |
| if (libDir != null) { |
| libDir = FileUtil.normalizeFile(libDir); |
| } |
| |
| String path = getPathToModules(libDir); |
| if (path.length() > 0) { |
| path = path + "/"; // NOI18N |
| } |
| final File oepeFile = new File(libDir, OEPE_CONTRIBUTIONS_JAR); |
| final String relPath = path; |
| |
| Jpa2Jars jars = getJpa2Jars(libDir, path); |
| |
| final String contribPath = path + jars.getJpa1Jar() + " " // NOI18N |
| + path + jars.getJpa2Jar(); |
| |
| |
| // oepe does not exist |
| if (!oepeFile.exists()) { |
| createContributionsJar(oepeFile, contribPath); |
| // exists so update cp |
| } else { |
| JarFile oepeJarFile = new JarFile(oepeFile); |
| try { |
| Manifest mf = oepeJarFile.getManifest(); |
| String cp = mf.getMainAttributes().getValue(Name.CLASS_PATH); |
| if (cp == null) { |
| cp = ""; // NOI18N |
| } |
| if ((!JPA_JAR_1_PATTERN.matcher(cp).matches() || !cp.contains(jars.getJpa1Jar())) |
| || (!JPA_JAR_2_PATTERN.matcher(cp).matches() || !cp.contains(jars.getJpa2Jar()))) { |
| |
| StringBuilder updated = new StringBuilder(); |
| for (String element : cp.split("\\s+")) { // NOI18N |
| if (!JPA_JAR_1_PATTERN.matcher(element).matches() && !JPA_JAR_2_PATTERN.matcher(element).matches()) { |
| updated.append(element).append(" "); // NOI18N |
| } |
| } |
| |
| updated.insert(0, " ").insert(0, jars.getJpa2Jar()).insert(0, relPath); // NOI18N |
| updated.insert(0, " ").insert(0, jars.getJpa1Jar()).insert(0, relPath); // NOI18N |
| |
| if (cp.length() == 0) { |
| updated.deleteCharAt(updated.length() - 1); |
| } |
| mf.getMainAttributes().put(Name.CLASS_PATH, updated.toString()); |
| replaceManifest(oepeFile, mf); |
| } |
| } finally { |
| oepeJarFile.close(); |
| } |
| } |
| |
| // update weblogic.jar |
| File weblogicFile = WebLogicLayout.getWeblogicJar(serverRoot); |
| JarFile weblogicJarFile = new JarFile(weblogicFile); |
| try { |
| Manifest wlManifest = weblogicJarFile.getManifest(); |
| String cp = wlManifest.getMainAttributes().getValue(Name.CLASS_PATH); |
| if (cp == null) { |
| cp = ""; // NOI18N |
| } |
| if (!cp.contains(OEPE_CONTRIBUTIONS_JAR)) { |
| if (cp.length() == 0) { |
| cp = OEPE_CONTRIBUTIONS_JAR; |
| } else { |
| cp = OEPE_CONTRIBUTIONS_JAR + " " + cp; // NOI18N |
| } |
| wlManifest.getMainAttributes().put(Name.CLASS_PATH, cp); |
| replaceManifest(weblogicFile, wlManifest); |
| } |
| } finally { |
| weblogicJarFile.close(); |
| } |
| } catch (IOException ex) { |
| Exceptions.printStackTrace(ex); |
| } finally { |
| notifyLibrariesChanged(); |
| } |
| } |
| |
| private void doDisable() { |
| if (!isSwitchSupported()) { |
| throw new IllegalStateException("JPA2 switching is not supported for WebLogic " + serverRoot); |
| } |
| |
| try { |
| File libDir = WLPluginProperties.getServerLibDirectory(serverRoot); |
| if (libDir != null) { |
| libDir = FileUtil.normalizeFile(libDir); |
| } |
| File oepeJarFile = new File(libDir, OEPE_CONTRIBUTIONS_JAR); |
| if (!oepeJarFile.exists() || !oepeJarFile.isFile()) { |
| return; |
| } |
| JarFile file = new JarFile(oepeJarFile); |
| try { |
| Manifest mf = file.getManifest(); |
| String cp = mf.getMainAttributes().getValue(Name.CLASS_PATH); |
| if (cp == null) { |
| return; |
| } |
| |
| StringBuilder builder = new StringBuilder(); |
| for (String element : cp.split("\\s+")) { // NOI18N |
| if (!JPA_JAR_1_PATTERN.matcher(element).matches() && !JPA_JAR_2_PATTERN.matcher(element).matches()) { |
| builder.append(element).append(" "); // NOI18N |
| } |
| } |
| if (builder.length() > 0) { |
| mf.getMainAttributes().put(Name.CLASS_PATH, |
| builder.substring(0, builder.length() - 1)); |
| } else { |
| mf.getMainAttributes().remove(Name.CLASS_PATH); |
| } |
| replaceManifest(oepeJarFile, mf); |
| } finally { |
| file.close(); |
| } |
| } catch (IOException ex) { |
| // TODO some exception/message to the user |
| Exceptions.printStackTrace(ex); |
| } finally { |
| notifyLibrariesChanged(); |
| } |
| } |
| |
| public boolean isEnabled() { |
| if (dm != null) { |
| return dm.getJ2eePlatformImpl().isJpa2Available(); |
| } else { |
| List<URL> classpath = WLJ2eePlatformFactory.getWLSClassPath(serverRoot, |
| WLPluginProperties.getMiddlewareHome(serverRoot), null); |
| for (URL url : classpath) { |
| URL file = FileUtil.getArchiveFile(url); |
| if (file != null && JPA_JAR_1_PATTERN.matcher(file.getFile()).matches()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |
| |
| public boolean isEnabledViaSmartUpdate() { |
| if (dm != null) { |
| dm.getJ2eePlatformImpl().getLibraries(); |
| for (LibraryImplementation lib : dm.getJ2eePlatformImpl().getLibraries()) { |
| List<URL> urls = lib.getContent("classpath"); // NOI18N |
| if (isEnabledViaSmartUpdate(urls)) { |
| return true; |
| } |
| } |
| return false; |
| } else { |
| List<URL> urls = WLJ2eePlatformFactory.getWLSClassPath(serverRoot, |
| WLPluginProperties.getMiddlewareHome(serverRoot), null); |
| return isEnabledViaSmartUpdate(urls); |
| } |
| } |
| |
| private boolean isEnabledViaSmartUpdate(List<URL> urls) { |
| if (urls != null) { |
| for (URL url : urls) { |
| URL file = FileUtil.getArchiveFile(url); |
| if (file != null && file.getFile().endsWith("BUG9923849_WLS103MP4.jar")) { // NOI18N |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Method sends classpath change event to any instance registered |
| * in the IDE and sharing the same server root. |
| */ |
| private void notifyLibrariesChanged() { |
| if (dm != null) { |
| dm.getJ2eePlatformImpl().notifyLibrariesChange(); |
| } |
| String[] urls = Deployment.getDefault().getInstancesOfServer(WLDeploymentFactory.SERVER_ID); |
| for (String url : urls) { |
| if (dm != null && url.equals(dm.getUri())) { |
| continue; |
| } |
| InstanceProperties props = InstanceProperties.getInstanceProperties(url); |
| if (props != null) { |
| String serverRootValue = props.getProperty(WLPluginProperties.SERVER_ROOT_ATTR); |
| File root = FileUtil.normalizeFile(new File(serverRootValue)); |
| if (root.equals(serverRoot)) { |
| try { |
| WLDeploymentManager manager = (WLDeploymentManager) |
| WLDeploymentFactory.getInstance().getDisconnectedDeploymentManager(url); |
| manager.getJ2eePlatformImpl().notifyLibrariesChange(); |
| } catch (DeploymentManagerCreationException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| } |
| } |
| } |
| } |
| |
| private void replaceManifest(File jarFile, Manifest manifest) throws IOException { |
| FileObject fo = FileUtil.toFileObject(jarFile); |
| String tmpName = FileUtil.findFreeFileName(fo.getParent(), |
| jarFile.getName(), "tmp"); // NOI18N |
| File tmpJar = new File(jarFile.getParentFile(), tmpName + ".tmp"); // NOI18N |
| try { |
| InputStream is = new BufferedInputStream( |
| new FileInputStream(jarFile)); |
| try { |
| OutputStream os = new BufferedOutputStream( |
| new FileOutputStream(tmpJar)); |
| try { |
| replaceManifest(is, os, manifest); |
| } finally { |
| os.close(); |
| } |
| } finally { |
| is.close(); |
| } |
| |
| if (tmpJar.renameTo(jarFile)) { |
| LOGGER.log(Level.FINE, "Successfully moved {0}", tmpJar); |
| return; |
| } |
| LOGGER.log(Level.FINE, "Byte to byte copy {0}", tmpJar); |
| copy(tmpJar, jarFile); |
| } finally { |
| tmpJar.delete(); |
| } |
| } |
| |
| private void replaceManifest(InputStream is, OutputStream os, Manifest manifest) throws IOException { |
| JarInputStream in = new JarInputStream(is); |
| try { |
| JarOutputStream out = new JarOutputStream(os, manifest); |
| try { |
| JarEntry entry = null; |
| byte[] temp = new byte[32768]; |
| while ((entry = in.getNextJarEntry()) != null) { |
| String name = entry.getName(); |
| if (name.equalsIgnoreCase("META-INF/MANIFEST.MF")) { // NOI18N |
| continue; |
| } |
| out.putNextEntry(entry); |
| while (in.available() != 0) { |
| int read = in.read(temp); |
| if (read != -1) { |
| out.write(temp, 0, read); |
| } |
| } |
| out.closeEntry(); |
| } |
| } finally { |
| out.close(); |
| } |
| } finally { |
| in.close(); |
| } |
| } |
| |
| private void createContributionsJar(File jarFile, String classpath) throws IOException { |
| //need to create zip file |
| OutputStream os = new BufferedOutputStream(new FileOutputStream(jarFile)); |
| try { |
| Manifest manifest = new Manifest(); |
| manifest.getMainAttributes().put(Name.MANIFEST_VERSION, "1.0"); // NOI18N |
| manifest.getMainAttributes().put(Name.CLASS_PATH, classpath); |
| JarOutputStream dest = new JarOutputStream(new BufferedOutputStream(os), manifest); |
| try { |
| dest.closeEntry(); |
| dest.finish(); |
| } finally { |
| dest.close(); |
| } |
| } finally { |
| os.close(); |
| } |
| } |
| |
| private void copy(File source, File dest) throws IOException { |
| InputStream is = new BufferedInputStream(new FileInputStream(source)); |
| try { |
| OutputStream os = new BufferedOutputStream(new FileOutputStream(dest)); |
| try { |
| FileUtil.copy(is, os); |
| } finally { |
| os.close(); |
| } |
| } finally { |
| is.close(); |
| } |
| } |
| |
| private String getPathToModules(File from) { |
| File mwHomeFile = null; |
| String mwHome = (dm != null) |
| ? dm.getProductProperties().getMiddlewareHome() |
| : WLProductProperties.getMiddlewareHome(serverRoot); |
| if (mwHome == null) { |
| if (serverRoot != null && serverRoot.getParentFile() != null) { |
| mwHomeFile = serverRoot.getParentFile(); |
| } |
| } else { |
| mwHomeFile = new File(mwHome); |
| } |
| if (mwHomeFile != null) { |
| File modules = FileUtil.normalizeFile(new File(mwHomeFile, "modules")); // NOI18N |
| String relativePath = getRelativePath(from, modules); |
| if (relativePath == null) { |
| // FIXME forward slashes |
| return modules.getAbsolutePath(); |
| } |
| return relativePath; |
| } |
| // just improbable fallback :( |
| return "../../../modules"; // NOI18N |
| } |
| |
| private Jpa2Jars getJpa2Jars(File libDir, String path) { |
| String jar1 = null; |
| String jar2 = null; |
| |
| if (libDir != null) { |
| File dir = new File(libDir, path); |
| |
| for (File candidate : dir.listFiles(new FilenameFilter() { |
| |
| @Override |
| public boolean accept(File dir, String name) { |
| return JPA_JAR_1_PATTERN.matcher(name).matches() || JPA_JAR_2_PATTERN.matcher(name).matches(); |
| } |
| })) { |
| if (jar1 == null && JPA_JAR_1_PATTERN.matcher(candidate.getName()).matches()) { |
| jar1 = candidate.getName(); |
| } else if (jar2 == null) { |
| jar2 = candidate.getName(); |
| } |
| } |
| } |
| // just fallback |
| if (jar1 == null) { |
| jar1 = JPA_JAR1_FALLBACK; |
| } |
| if (jar2 == null) { |
| jar2 = JPA_JAR2_FALLBACK; |
| } |
| return new Jpa2Jars(jar1, jar2); |
| } |
| |
| // package for testing only |
| static String getRelativePath(File from, File to) { |
| String toPath = to.getAbsolutePath(); |
| String fromPath = from.getAbsolutePath(); |
| if (toPath.startsWith(fromPath)) { |
| if (toPath.length() == fromPath.length()) { |
| return ""; |
| } |
| StringBuilder builder = new StringBuilder(); |
| File currentPath = to; |
| while (!currentPath.equals(from)) { |
| builder.insert(0, currentPath.getName()); |
| builder.insert(0, "/"); // NOI18N |
| currentPath = currentPath.getParentFile(); |
| } |
| return builder.substring(1); |
| } else { |
| File parent = from.getParentFile(); |
| if (parent == null) { |
| return null; |
| } else { |
| return "../" + getRelativePath(parent, to); // NOI18N |
| } |
| } |
| } |
| |
| private static class Jpa2Jars { |
| |
| private final String Jpa1Jar; |
| |
| private final String Jpa2Jar; |
| |
| public Jpa2Jars(String Jpa1Jar, String Jpa2Jar) { |
| this.Jpa1Jar = Jpa1Jar; |
| this.Jpa2Jar = Jpa2Jar; |
| } |
| |
| public String getJpa1Jar() { |
| return Jpa1Jar; |
| } |
| |
| public String getJpa2Jar() { |
| return Jpa2Jar; |
| } |
| } |
| } |