/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.faces.tools; import java.io.BufferedReader; 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.InputStreamReader; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This updater supports GFv1, v2, and v3. * @author edburns */ public class GlassfishUpdater { private enum Version { GFv1orv2, GFv3 } private static final String ASADMIN_NAME = "asadmin"; private static final String BACKUP_SUFFIX = "jsfbak"; /** Creates a new instance of GlassfishUpdater */ protected GlassfishUpdater() { } protected static File libDir = null; protected static File modulesDir = null; protected static Version version = null; public static void main(String args[]) throws IOException { if (0 == args.length) { printUsage(); return; } File testFile = null, gfInstallDir = new File(args[0]); // Have we been given a directory? if (!gfInstallDir.isDirectory()) { printUsage(); return; } // Is it a glassfish install directory? testFile = new File(gfInstallDir,"bin"); File [] files = testFile.listFiles(); boolean foundAsdmin = false; for (File cur : files) { if (-1 != cur.getName().indexOf("asadmin")) { foundAsdmin = true; break; } } if (!foundAsdmin) { printUsage(); return; } // detect the GF version. If GF_HOME/modules exists, this // is a v3 installation we're updating. We'll have to take different // action. modulesDir = new File(gfInstallDir, "modules"); if (modulesDir.exists() && modulesDir.isDirectory()) { version = Version.GFv3; } else { version = Version.GFv1orv2; } // Get the glassfish lib directory libDir = new File(gfInstallDir, "lib"); if (!libDir.isDirectory()) { printUsage(); return; } if (licenseAccepted()) { System.out.println("Updating glassfish at\n" + gfInstallDir.toString()); System.out.println("with new JSF jars."); if (Version.GFv1orv2 == version) { stripJsfFromJavaEEJar(libDir); unpackJsfJarsToLib(libDir); } else { try { updateV3Jars(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } } } public static boolean licenseAccepted() throws IOException { boolean result = false; InputStream is = Thread.currentThread().getContextClassLoader(). getResourceAsStream("BINARY_LICENSE.txt"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; while (null != (line = br.readLine())) { System.out.println(line); } System.out.print("Do you accept the above license terms? (type yes or no):"); br = new BufferedReader(new InputStreamReader(System.in)); line = br.readLine(); result = (null != line) && line.equals("yes"); return result; } protected static boolean printUsageCalled = false; public static void printUsage() { printUsageCalled = true; System.err.println("Usage: java -jar glassfish-jsf-update.jar <glassfish install directory>"); System.err.println("\t<glassfish install directory> is the path to the\n\tglassfish binary install."); } public static void stripJsfFromJavaEEJar(File libDir) throws IOException { if (!javaEEJarHasJsfClasses(libDir)) { return; } File javaEEJarCopy = new File(libDir, "javaee.jar.copy"), javaEEJar = new File (libDir, "javaee.jar"), javaEEJarOrig = new File(libDir, getBackupFilename(libDir, "javaee.jar")); javaEEJarCopy.delete(); JarInputStream origJarStream = new JarInputStream(new FileInputStream(javaEEJar)); JarOutputStream copyJarStream = new JarOutputStream(new FileOutputStream(javaEEJarCopy)); JarEntry newEntry = null, cur = null; Pattern pat = Pattern.compile(".*javax.faces.*"); Matcher mat = null; byte[] buf = new byte[1024]; int n = 0; while (null != (cur = origJarStream.getNextJarEntry())) { mat = pat.matcher(cur.getName()); // If the current entry does not include javax.faces... if (!mat.matches()) { // copy it to the newJar. newEntry = new JarEntry(cur.getName()); copyJarStream.putNextEntry(newEntry); while((n = origJarStream.read(buf, 0, buf.length)) != -1) { copyJarStream.write(buf, 0, n); } } } origJarStream.close(); copyJarStream.close(); javaEEJar.renameTo(javaEEJarOrig); javaEEJarCopy.renameTo(javaEEJar); } public static boolean javaEEJarHasJsfClasses(File libDir) throws IOException { boolean result = false; File javaEEJar = new File (libDir, "javaee.jar"); JarInputStream origJarStream = new JarInputStream(new FileInputStream(javaEEJar)); JarEntry cur = null; Pattern pat = Pattern.compile(".*javax.faces.*"); Matcher mat = null; cur = origJarStream.getNextJarEntry(); while (null != cur) { mat = pat.matcher(cur.getName()); // If the current entry does not include javax.faces... if (mat.matches()) { result = true; } cur = origJarStream.getNextJarEntry(); } origJarStream.close(); return result; } public static void unpackJsfJarsToLib(File libDir) throws IOException { InputStream is = Thread.currentThread().getContextClassLoader(). getResourceAsStream("jsf-api.jar"); File jsfApiCopy = new File(libDir, getBackupFilename(libDir, "jsf-api.jar")), jsfApi = new File(libDir, "jsf-api.jar"), jsfImplCopy = new File(libDir, getBackupFilename(libDir, "jsf-impl.jar")), jsfImpl = new File(libDir, "jsf-impl.jar"); jsfApiCopy.delete(); jsfImplCopy.delete(); jsfApi.renameTo(jsfApiCopy); jsfImpl.renameTo(jsfImplCopy); FileOutputStream fos = new FileOutputStream(jsfApi); int n = 0; while (-1 != (n = is.read())) { fos.write(n); } is.close(); fos.close(); is = Thread.currentThread().getContextClassLoader(). getResourceAsStream("jsf-impl.jar"); fos = new FileOutputStream(jsfImpl); while (-1 != (n = is.read())) { fos.write(n); } is.close(); fos.close(); } protected static String getBackupFilename(File libDir, String filename) { File [] files = libDir.listFiles(); Pattern pat = Pattern.compile(".*" + BACKUP_SUFFIX + "[0-9]*"); Matcher mat = null; ArrayList<File> backupFiles = new ArrayList<File>(); for (File cur : files) { mat = pat.matcher(cur.getName()); // If the current entry is a backup file... if (mat.matches()) { // add it to the list. backupFiles.add(cur); } } int i = 1; int curInt = 0; String curSuffix = null, curName = null; if (0 < backupFiles.size()) { // Find the highest backup number and go one more. for (File cur : backupFiles) { curName = cur.getName(); curSuffix = curName.substring(curName.indexOf(BACKUP_SUFFIX)); if (BACKUP_SUFFIX.length() < curSuffix.length()) { curInt = Integer.valueOf(curSuffix. substring(BACKUP_SUFFIX.length())).intValue(); if (i == curInt) { i = curInt + 1; } else if (i < curInt) { i = curInt; } } } } return filename + BACKUP_SUFFIX + i; } // Methods for updating V3 private static Map<String,String> mapping = new HashMap<String,String>(2, 1.0f); static { mapping.put("javax.javaee", "jsf-api.jar"); mapping.put("jsf-connector", "jsf-impl.jar"); } private static void updateV3Jars() throws Exception { for (Map.Entry<String,String> entry : mapping.entrySet()) { final String targetKey = entry.getKey(); File modulesDirTmp; if ("jsf-connector".equals(targetKey)) { modulesDirTmp = new File(modulesDir, "web"); } else { modulesDirTmp = modulesDir; } String[] files = modulesDirTmp.list(new FilenameFilter() { public boolean accept(File dir, String name) { return name.startsWith(targetKey) && name.endsWith(".jar"); } }); if (files.length != 1) { throw new RuntimeException("Multiple .jar files starting with " + targetKey + ". Update cannot proceed"); } File f = new File(modulesDirTmp, files[0]); // we now have the jar we need to backup String backupName = getBackupFilename(modulesDirTmp, files[0]); File backup = new File(modulesDirTmp, backupName); FileInputStream in = new FileInputStream(f); FileOutputStream out = new FileOutputStream(backup); byte[] buf = new byte[1024]; for (int total = in.read(buf); total != -1; total = in.read(buf)) { out.write(buf, 0, total); } out.flush(); out.close(); in.close(); // backup created. Now update the file by removing the // javax.faces or com.sun.faces entries. String jarSource = entry.getValue(); String pkg = ((jarSource.equals("jsf-api.jar") ? "javax/faces" : "com/sun/faces")); f = new File(modulesDirTmp, files[0]); String copyName = files[0] + ".copy"; File copy = new File(modulesDirTmp, copyName); JarInputStream jarIn = new JarInputStream(new FileInputStream(f)); JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(copy), jarIn.getManifest()); JarEntry newEntry = null, cur = null; Matcher mat = null; int n; while (null != (cur = jarIn.getNextJarEntry())) { // If the current entry does not include javax.faces... if (!cur.getName().startsWith(pkg)) { // copy it to the newJar. newEntry = new JarEntry(cur.getName()); jarOut.putNextEntry(newEntry); while ((n = jarIn.read(buf, 0, buf.length)) != -1) { jarOut.write(buf, 0, n); } } } jarIn.close(); jarOut.flush(); jarOut.close(); // ok, the copy is now without the javax.faces classes. // read in from the packaged jsf-api.jar and add the entries jarIn = new JarInputStream(Thread.currentThread() .getContextClassLoader(). getResourceAsStream(jarSource)); JarInputStream jarInCopy = new JarInputStream(new FileInputStream(copy)); jarOut = new JarOutputStream(new FileOutputStream(f), jarInCopy.getManifest()); while (null != (cur = jarIn.getNextJarEntry())) { if (cur.getName().contains("MANIFEST.MF") || cur.getName() .contains("com.sun.faces.spi.injectionprovider")) { continue; } // copy it to the newJar. newEntry = new JarEntry(cur.getName()); jarOut.putNextEntry(newEntry); while ((n = jarIn.read(buf, 0, buf.length)) != -1) { jarOut.write(buf, 0, n); } } while (null != (cur = jarInCopy.getNextJarEntry())) { // copy it to the newJar. newEntry = new JarEntry(cur.getName()); try { jarOut.putNextEntry(newEntry); } catch (Exception e) { continue; } while ((n = jarInCopy.read(buf, 0, buf.length)) != -1) { jarOut.write(buf, 0, n); } } jarIn.close(); jarInCopy.close(); jarOut.flush(); jarOut.close(); copy.delete(); } } }