User: mnf999 Date: 02/01/19 19:38:23 Added: src/main/org/jboss/deployment SARDeployer.java Log: The new SARDeployer Revision Changes Path 1.1 jboss/src/main/org/jboss/deployment/SARDeployer.java Index: SARDeployer.java =================================================================== /* * JBoss, the OpenSource J2EE webOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.deployment; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.util.StringTokenizer; import java.util.jar.JarFile; import java.util.Enumeration; import java.util.jar.JarEntry; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.ReflectionException; import javax.management.RuntimeErrorException; import javax.management.RuntimeMBeanException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.jboss.deployment.DeploymentInfo; import org.jboss.system.Service; import org.jboss.system.ServiceControllerMBean; import org.jboss.system.ServiceLibraries; import org.jboss.system.ServiceMBeanSupport; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * This is the main Service Deployer API. * * @see org.jboss.system.Service * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">David Maplesden</a> * @author <a href="mailto:[EMAIL PROTECTED]">David Jencks</a> * @version $Revision: 1.1 $ <p> * * <b>20010830 marc fleury:</b> * <ul>initial import * <li> * </ul> * * <p><b>20010905 david maplesden:</b> * <ul> * <li>Changed deployment procedure to deploy all listed mbeans, then * initialise them all before finally starting them all. Changed services * sets to lists to maintain ordering. * </ul> * * <b>20010908 david jencks</b> * <ol> * <li> fixed tabs to spaces and log4j logging. Made the urlToServiceSet * map actually use the url supplied to deploy. Made postRegister use * deploy. Made undeploy work, and implemented sar dependency management * and recursive deploy/undeploy. * </ol> * * <p><b>20010907 david maplesden:</b> * <ul> * <li>Added support for "depends" tag * </ul> * * <p><b>20011210 marc fleury:</b> * <ul> * <li>Removing the classpath dependency to explicit jars * </ul> * <p><b>20011211 marc fleury:</b> * <ul> * <li>rewrite * </ul> */ public class SARDeployer extends ServiceMBeanSupport implements SARDeployerMBean { // Attributes -------------------------------------------------------- private ObjectName objectName; //Find all the deployment info for a url private final Map urlToDeploymentInfoMap = new HashMap(); //Find what package an mbean came from. private final Map objectNameToSupplyingPackageMap = new HashMap(); // Public -------------------------------------------------------- /** * Gets the Name of the ServiceDeployer object * * @return returns "ServiceDeployer" */ public String getName() { return "ServiceDeployer"; } /** * Gets the FilenameFilter that the AutoDeployer uses to decide which files * will be deployed by the ServiceDeployer. Currently .jsr, .sar, and files * ending in service.xml are accepted. * * @return The FileNameFilter for use by the AutoDeployer. */ public boolean accepts(DeploymentInfo di) { return (di.url.toString().endsWith(".sar") || di.url.toString().endsWith("service.xml")); } public void init(DeploymentInfo di) throws DeploymentException { try { // resolve the watch if (di.url.getProtocol().startsWith("http")) { // We watch the top only, no directory support di.watch = di.url; } else if(di.url.getProtocol().startsWith("file")) { File file = new File (di.url.getFile()); // If not directory we watch the package if (!file.isDirectory()) di.watch = di.url; // If directory we watch the xml files else di.watch = new URL(di.url, "META-INF/jboss-service.xml"); } // Get the document parseDocument(di); // In case there is a dependent classpath defined parse it // This creates parseXMLClasspath(di); //Copy local directory if local-directory element is present NodeList lds = di.document.getElementsByTagName("local-directory"); log.debug("about to copy " + lds.getLength() + " local directories"); for (int i = 0; i< lds.getLength(); i++) { Element ld = (Element)lds.item(i); String path = ld.getAttribute("path"); log.debug("about to copy local directory at " + path); File jbossHomeDir = new File(System.getProperty("jboss.system.home")); File localBaseDir = new File(jbossHomeDir, "db"+File.separator); //Get the url of the local copy from the classloader. log.debug("copying from " + di.localUrl.toString() + path); log.debug("copying to " + localBaseDir); inflateJar(di.localUrl, localBaseDir, path); } // end of for () } catch (Exception e) { log.error("Problem in init", e); throw new DeploymentException(e.getMessage()); } } public void deploy(DeploymentInfo di) throws DeploymentException { try { // install the MBeans in this descriptor log.info("Deploying SAR: url " + di.url); List mbeans = di.mbeans; mbeans.clear(); NodeList nl = di.document.getElementsByTagName("mbean"); for (int i = 0; i < nl.getLength(); i++) { Element mbean = (Element)nl.item(i); log.debug("deploying with ServiceController mbean " + mbean); ObjectName service = (ObjectName)invoke( getServiceControllerName(), "install", new Object[]{mbean}, new String[]{"org.w3c.dom.Element"}); if (service != null) { mbeans.add(service); // objectNameToSupplyingPackageMap.put(service, url); } } // create the services Iterator iterator = di.mbeans.iterator(); while (iterator.hasNext()) { ObjectName service = (ObjectName) iterator.next(); // The service won't be created until explicitely dependent mbeans are created invoke( getServiceControllerName(), "create", new Object[]{service}, new String[]{"javax.management.ObjectName"}); } // start the services Iterator iterator2 = di.mbeans.iterator(); while (iterator2.hasNext()) { ObjectName service2 = (ObjectName) iterator2.next(); // The service won't be started until explicitely dependent mbeans are started invoke( getServiceControllerName(), "start", new Object[]{service2}, new String[]{"javax.management.ObjectName"}); } } catch (Exception e ) {log.error("Error in deploy ", e);} } protected void parseXMLClasspath(DeploymentInfo di) throws DeploymentException { Set classpath = new HashSet(); NodeList classpaths = di.document.getElementsByTagName("classpath"); for (int i = 0; i < classpaths.getLength(); i++) { Element classpathElement = (Element)classpaths.item(i); log.debug("found classpath " + classpath); //String codebase = System.getProperty("jboss.system.libraryDirectory"); String codebase = ""; String archives = ""; //Does it specify a codebase? if (classpathElement != null) { log.debug("setting up classpath " + classpath); // Load the codebase codebase = classpathElement.getAttribute("codebase").trim(); if ("".equals(codebase) || ".".equals(codebase)) { //does this work with http??? // marcf: for http we could just get the substring to the last "/" codebase = new File(di.url.getProtocol() + "://" + di.url.getFile()).getParent(); } // Do we have a relative codebase? if (!(codebase.startsWith("http:") || codebase.startsWith("file:"))) { // put the jboss/system base in front of it codebase = System.getProperty("jboss.system.installationURL")+codebase; } // Let's make sure the formatting of the codebase ends with the / if (codebase.startsWith("file:") && !codebase.endsWith(File.separator)) { codebase += File.separator; } else if (codebase.startsWith("http:") && !codebase.endsWith("/")) { codebase += "/"; } log.debug("codebase is " + codebase); //get the archives string archives = classpathElement.getAttribute("archives").trim(); log.debug("archives are " + archives); } if (codebase.startsWith("file:") && archives.equals("*")) { try { File dir = new File(codebase.substring(5)); // The patchDir can only be a File one, local File[] jars = dir.listFiles( new java.io.FileFilter() { /** * filters for jar and zip files in the local directory. * * @param pathname Path to the candidate file. * @return True if the file is a jar or zip * file. */ public boolean accept(File pathname) { String name2 = pathname.getName(); return (name2.endsWith(".jar") || name2.endsWith(".zip")); } } ); for (int j = 0; jars != null && j < jars.length; j++) { classpath.add(jars[j].getCanonicalFile().toURL()); } } catch (Exception e) { log.error("problem listing files in directory", e); throw new DeploymentException(e.getMessage()); } } // We have an archive whatever the codebase go ahead and load the libraries else if (!archives.equals("")) { // We have a real codebase specified in xml // We add it to the classpath so we load files from it (http/file will work) if (!codebase.equals("")) { try { // Add the codebase to the classpath classpath.add( new URL(codebase)); } catch (Exception e2) { log.error("Couldn't create URL for codebase "+codebase, e2); throw new DeploymentException(e2.getMessage()); } } // Still no codebase? safeguard if (codebase.equals("")) codebase = System.getProperty("jboss.system.libraryDirectory"); if (archives.equals("*") || archives.equals("")) { // Safeguard if (!codebase.startsWith("file:") && archives.equals("*")) throw new DeploymentException("No wildcard permitted in http deployment you must specify individual jars"); try { File dir = new File(codebase.substring(5)); // The patchDir can only be a File one, local File[] jars = dir.listFiles( new java.io.FileFilter() { /** * filters for jar and zip files in the local directory. * * @param pathname Path to the candidate file. * @return True if the file is a jar or zip * file. */ public boolean accept(File pathname) { String name2 = pathname.getName(); return name2.endsWith(".jar") || name2.endsWith(".zip"); } } ); for (int j = 0; jars != null && j < jars.length; j++) { classpath.add(jars[j].getCanonicalFile().toURL()); } } catch (Exception e) { log.error("problem listing files in directory", e); throw new DeploymentException(e.getMessage()); } } else // A real archive listing (as opposed to wildcard) { StringTokenizer jars = new StringTokenizer(archives, ","); //iterate through the packages in archives while (jars.hasMoreTokens()) { // The format is simple codebase + jar try { classpath.add(new URL(codebase +jars.nextToken().trim()));} catch (MalformedURLException mfue) { log.error("couldn't resolve package reference: ", mfue);} // end of try-catch } } } else //codebase is empty and archives is empty but we did have a classpath entry { throw new DeploymentException("A classpath entry was declared but no codebase and no jars specified. Please fix jboss-service.xml in your configuration"); } } //Ok, now we've found the list of urls we need... deploy their classes. Iterator jars = classpath.iterator(); URL neededUrl = null; while (jars.hasNext()) { neededUrl = (URL)jars.next(); // Call the main deployer with it try { // Create a new Deployment not as a subdeployment, // An external package is not a "subdeployment" it is a stand alone // deployment scanned as such DeploymentInfo sub = new DeploymentInfo(neededUrl, null); invoke( new ObjectName(org.jboss.deployment.MainDeployerMBean.OBJECT_NAME), "deploy", new Object[] {sub}, new String[] {"org.jboss.deployment.DeploymentInfo"}); } catch (Exception e) {log.error(e);} log.debug("deployed classes for " + neededUrl); } // end of while () } /** * Undeploys the package at the url string specified. This will: Undeploy * packages depending on this one. Stop, destroy, and unregister all the * specified mbeans Unload this package and packages this package deployed * via the classpath tag. Keep track of packages depending on this one that * we undeployed so that they can be redeployed should this one be * redeployed. * * @param urlString The location of the package to be * undeployed (used to index the packages, not to read service.xml on * undeploy! * @exception MalformedURLException Thrown if the url string is not valid. * @exception IOException Thrown if something could not be read. * @exception DeploymentException Thrown if the package could not be * undeployed */ public void undeploy(DeploymentInfo sdi) throws DeploymentException { log.debug("undeploying document " + sdi.url); List services = sdi.mbeans; int lastService = services.size(); //stop services in reverse order. for (ListIterator i = services.listIterator(lastService); i.hasPrevious();) { ObjectName name = (ObjectName)i.previous(); log.debug("stopping mbean " + name); invoke(getServiceControllerName(), "stop", new Object[] {name}, new String[] {"javax.management.ObjectName"}); } for (ListIterator i = services.listIterator(lastService); i.hasPrevious();) { ObjectName name = (ObjectName)i.previous(); log.debug("destroying mbean " + name); invoke(getServiceControllerName(), "destroy", new Object[] {name}, new String[] {"javax.management.ObjectName"}); } for (ListIterator i = services.listIterator(lastService); i.hasPrevious();) { ObjectName name = (ObjectName)i.previous(); log.debug("removing mbean " + name); invoke(getServiceControllerName(), "remove", new Object[] {name}, new String[] {"javax.management.ObjectName"}); //we don't supply it any more, maybe someone else will later. // objectNameToSupplyingPackageMap.remove(name); } } /** * MBeanRegistration interface. Get the mbean server. * This is the only deployer that registers with the MainDeployer here * * @param server Our mbean server. * @param name our proposed object name. * @return our actual object name * @exception java.lang.Exception Thrown if we are supplied an invalid name. */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws java.lang.Exception { super.preRegister(server, name); log.debug("ServiceDeployer preregistered with mbean server"); objectName = name == null ? new ObjectName(OBJECT_NAME) : name; // Register with the main deployer server.invoke( new ObjectName(org.jboss.deployment.MainDeployerMBean.OBJECT_NAME), "addDeployer", new Object[] {this}, new String[] {"org.jboss.deployment.DeployerMBean"}); return objectName; } /** * PostRegister initialized the ServiceDeployed mbean and tries to load a * spine package to set up basic jboss. At the moment the spine package * should be jboss-service.xml or (deprecated) jboss.jcml. Soon we should * have an actual sar with the code as well as configuration info. * * @param registrationDone Description of Parameter */ /*public void postRegister(java.lang.Boolean registrationDone) { try { super.postRegister(registrationDone); //Start us up, which also sets up the deploy temp directory invoke(getServiceControllerName(), "create", new Object[] {objectName}, new String[] {"javax.management.ObjectName"}); invoke(getServiceControllerName(), "start", new Object[] {objectName}, new String[] {"javax.management.ObjectName"}); } catch (Exception e) { log.error("Problem postregistering ServiceDeployer", e); } } */ public void preDeregister() throws Exception { server.invoke( new ObjectName(org.jboss.deployment.MainDeployerMBean.OBJECT_NAME), "removeDeployer", new Object[] {this}, new String[] {"org.jboss.deployment.DeployerMBean"}); } protected void parseDocument(DeploymentInfo di) throws DeploymentException { try { DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); InputStream stream = null; // If we are in a xml only get the URL if (di.isXML) stream = di.localUrl.openStream(); // Else load from the jar or directory else stream = di.localCl.getResourceAsStream("META-INF/jboss-service.xml"); InputSource is = new InputSource(stream); di.document = parser.parse(is); } catch (SAXException e) { log.warn("SaxException getting document:", e); throw new DeploymentException(e.getMessage()); } catch (ParserConfigurationException pce) { log.warn("ParserConfigurationException getting document:", pce); throw new DeploymentException(pce.getMessage()); } catch (Exception e) { log.warn("Exception getting document:", e); throw new DeploymentException(e.getMessage()); } // end of try-catch } // Private -------------------------------------------------------- private ObjectName getServiceControllerName() throws DeploymentException { try { return new ObjectName(ServiceControllerMBean.OBJECT_NAME);} catch (Exception e) {throw new DeploymentException ("Couldn't get the ObjectName for the ServiceControllerMBean");} } private void removeMBeans(URL url, DeploymentInfo sdi) throws DeploymentException { } /** * The <code>inflateJar</code> copies the jar entries * from the jar url jarUrl to the directory destDir. * It can be used on the whole jar, a directory, or * a specific file in the jar. * * @param jarUrl the <code>URL</code> if the directory or entry to copy. * @param destDir the <code>File</code> value of the directory in which to * place the inflated copies. * @exception DeploymentException if an error occurs * @exception IOException if an error occurs */ protected void inflateJar(URL url, File destDir, String path) throws DeploymentException, IOException { /* //Why doesn't this work???? Maybe in java 1.4? URL jarUrl; try { jarUrl = new URL("jar:" + url.toString() + "!/"); } catch (MalformedURLException mfue) { throw new DeploymentException("Oops! Couldn't convert URL to a jar URL", mfue); } JarURLConnection jarConnection = (JarURLConnection)jarUrl.openConnection(); JarFile jarFile = jarConnection.getJarFile(); */ String filename = url.getFile(); JarFile jarFile = new JarFile(filename); try { for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) { JarEntry entry = (JarEntry)e.nextElement(); String name = entry.getName(); if (path == null || name.startsWith(path)) { File outFile = new File(destDir, name); if (!outFile.exists()) { if (entry.isDirectory()) outFile.mkdirs(); else { InputStream in = jarFile.getInputStream(entry); OutputStream out = new FileOutputStream(outFile); try { byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) > 0) out.write(buffer, 0, read); } finally { in.close();out.close(); } } } // end of if (outFile.exists()) } // end of if (matches path) } } finally { jarFile.close(); } } /** * Parse an object name from the given element attribute 'name'. * * @param element Element to parse name from. * @return Object name. * * @throws ConfigurationException Missing attribute 'name' * (thrown if 'name' is null or ""). * @throws MalformedObjectNameException */ private ObjectName parseObjectName(final Element element) throws org.jboss.system.ConfigurationException, MalformedObjectNameException { String name = ((org.w3c.dom.Text)element.getFirstChild()).getData().trim(); if (name == null || name.trim().equals("")) { throw new org.jboss.system.ConfigurationException ("Name element must have a value."); } return new ObjectName(name); } /* Calls server.invoke, unwraps exceptions, and returns server output */ private Object invoke(ObjectName name, String method, Object[] args, String[] sig) { try { return server.invoke(name, method, args, sig); } catch (MBeanException mbe) { log.error("Mbean exception while executing " + method + " on " + args, mbe.getTargetException()); } catch (RuntimeMBeanException rbe) { log.error("Runtime Mbean exception while executing " + method + " on " + args, rbe.getTargetException()); } catch (RuntimeErrorException ree) { log.error("Runtime Error exception while executing " + method + " on " + args, ree.getTargetError()); } catch (ReflectionException re) { log.error("ReflectionException while executing " + method + " on " + args, re); } catch (InstanceNotFoundException re) { log.error("InstanceNotFoundException while executing " + method + " on " + args, re); } catch (Exception e) { log.error("Exception while executing " + method + " on " + args, e); } return null; } }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development