/* * IronJacamar, a Java EE Connector Architecture implementation * Copyright 2016, Red Hat Inc, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the Eclipse Public License 1.0 as * published by the Free Software Foundation. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse * Public License for more details. * * You should have received a copy of the Eclipse Public License * along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.ironjacamar.rarinfo; import org.ironjacamar.common.annotations.Annotations; import org.ironjacamar.common.api.metadata.Defaults; import org.ironjacamar.common.api.metadata.common.Pool; import org.ironjacamar.common.api.metadata.common.Recovery; import org.ironjacamar.common.api.metadata.common.TransactionSupportEnum; import org.ironjacamar.common.api.metadata.resourceadapter.AdminObject; import org.ironjacamar.common.api.metadata.resourceadapter.ConnectionDefinition; import org.ironjacamar.common.api.metadata.spec.ConfigProperty; import org.ironjacamar.common.api.metadata.spec.Connector; import org.ironjacamar.common.api.metadata.spec.Connector.Version; import org.ironjacamar.common.api.metadata.spec.MessageListener; import org.ironjacamar.common.api.metadata.spec.RequiredConfigProperty; import org.ironjacamar.common.api.metadata.spec.ResourceAdapter; import org.ironjacamar.common.api.metadata.spec.XsdString; import org.ironjacamar.common.metadata.common.CredentialImpl; import org.ironjacamar.common.metadata.common.PoolImpl; import org.ironjacamar.common.metadata.common.RecoveryImpl; import org.ironjacamar.common.metadata.common.SecurityImpl; import org.ironjacamar.common.metadata.common.XaPoolImpl; import org.ironjacamar.common.metadata.resourceadapter.AdminObjectImpl; import org.ironjacamar.common.metadata.resourceadapter.ConnectionDefinitionImpl; import org.ironjacamar.common.metadata.spec.RaParser; import org.ironjacamar.common.spi.annotations.repository.AnnotationRepository; import org.ironjacamar.common.spi.annotations.repository.AnnotationScanner; import org.ironjacamar.common.spi.annotations.repository.AnnotationScannerFactory; import org.ironjacamar.core.util.Injection; import org.ironjacamar.validator.Validation; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.Reader; import java.io.StringReader; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.resource.ResourceException; import javax.resource.spi.ManagedConnection; import javax.resource.spi.ManagedConnectionFactory; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * rar info main class * * @author Jeff Zhang * @author Flavia Rainone */ public class Main { /** Exit codes */ private static final int SUCCESS = 0; private static final int ERROR = 1; private static final int OTHER = 2; private static final String EXCEPTIONS_FILE = "-exceptions.txt"; private static final String REPORT_FILE = "-report.txt"; private static final String RAXML_FILE = "META-INF/ra.xml"; private static final String tempdir = System.getProperty("java.io.tmpdir"); private static final String subdir = "/jca/"; private static Set<Class<?>> validTypes; private static final String ARGS_CP = "-classpath"; private static final String ARGS_STDOUT = "--stdout"; private static final String ARGS_OUT = "-o"; private static File root = null; /** * Connector type */ enum ConnectorType { /** Inbound */ INBOUND ("InBound"), /** Outbound */ OUTBOUND ("OutBound"), /** Bidirectional */ BIDIRECTIONAL ("Bidirectional"); private final String value; /** * Constructor. * @param value description */ ConnectorType(String value) { this.value = value; } /** * Returns the connector type description. * @return returns the description */ public String toString() { return value; } }; static { validTypes = new HashSet<>(); validTypes.add(boolean.class); validTypes.add(Boolean.class); validTypes.add(byte.class); validTypes.add(Byte.class); validTypes.add(short.class); validTypes.add(Short.class); validTypes.add(int.class); validTypes.add(Integer.class); validTypes.add(long.class); validTypes.add(Long.class); validTypes.add(float.class); validTypes.add(Float.class); validTypes.add(double.class); validTypes.add(Double.class); validTypes.add(char.class); validTypes.add(Character.class); validTypes.add(String.class); } private static void loadNativeLibraries(File root) { if (root != null && root.exists()) { List<String> libs = null; if (root.isDirectory()) { if (root.listFiles() != null) { for (File f : root.listFiles()) { String fileName = f.getName().toLowerCase(Locale.US); if (fileName.endsWith(".a") || fileName.endsWith(".so") || fileName.endsWith(".dll")) { if (libs == null) libs = new ArrayList<>(); libs.add(f.getAbsolutePath()); } } } else { System.out.println("Root is a directory, but there were an I/O error: " + root.getAbsolutePath()); } } if (libs != null) { for (String lib : libs) { try { SecurityActions.load(lib); System.out.println("Loaded library: " + lib); } catch (Throwable t) { t.printStackTrace(System.err); System.out.println("Unable to load library: " + lib); } } } } } /** * Main * @param args args */ public static void main(String[] args) { final int argsLength = args.length; if (argsLength < 1) { usage(); System.exit(OTHER); } String rarFile = ""; String[] cps = null; boolean stdout = false; String reportFile = ""; for (int i = 0; i < argsLength; i++) { String arg = args[i]; if (arg.equals(ARGS_CP)) { cps = args[++i].split(System.getProperty("path.separator")); } else if (arg.equals(ARGS_STDOUT)) { stdout = true; } else if (arg.equals(ARGS_OUT)) { reportFile = args[++i]; } else if (arg.endsWith("rar")) { rarFile = arg; } else { usage(); System.exit(OTHER); } } int exitCode = rarInfo(rarFile, cps, stdout, reportFile); if (exitCode == SUCCESS) { System.out.println("Done."); } System.exit(exitCode); } /** * Runs the rar info tool. * * @param rarFile the name of the rar file * @param cps the class path necessary for loading rarFile, if any * @param stdout indicates whether the output should be printed in System.out * @param reportFile the name of a report file, in case the output will be printed in System.out * @return the system exit code */ static int rarInfo(String rarFile, String[] cps, boolean stdout, String reportFile) { PrintStream error = null; PrintStream out = null; ZipFile zipFile = null; URLClassLoader cl = null; try { zipFile = new ZipFile(rarFile); boolean existNativeFile = false; Connector connector = null; ArrayList<String> names = new ArrayList<>(); ArrayList<String> xmls = new ArrayList<>(); Enumeration<? extends ZipEntry> zipEntries = zipFile.entries(); while (zipEntries.hasMoreElements()) { ZipEntry ze = zipEntries.nextElement(); String name = ze.getName(); names.add(name); if (name.endsWith(".xml") && name.startsWith("META-INF") && !name.endsWith("pom.xml")) xmls.add(name); if (name.endsWith(".so") || name.endsWith(".a") || name.endsWith(".dll")) existNativeFile = true; if (name.equals(RAXML_FILE)) { InputStream raIn = zipFile.getInputStream(ze); XMLStreamReader raXsr = XMLInputFactory.newInstance().createXMLStreamReader(raIn); RaParser parser = new RaParser(); connector = parser.parse(raXsr); raIn.close(); } } root = getRoot(rarFile); loadNativeLibraries(root); cl = loadClass(cps); // Annotation scanning if (scanArchive(connector)) { Annotations annotator = new Annotations(); AnnotationScanner scanner = AnnotationScannerFactory.getAnnotationScanner(); AnnotationRepository repository = scanner.scan(cl.getURLs(), cl); connector = annotator.merge(connector, repository, cl); } if (connector == null) { System.out.println("can't parse ra.xml"); return OTHER; } if (stdout) { out = System.out; } else if (!reportFile.isEmpty()) { out = new PrintStream(reportFile); } else { out = new PrintStream(rarFile.substring(0, rarFile.length() - 4) + REPORT_FILE); } if (stdout) { error = System.out; } else { error = new PrintStream(rarFile.substring(0, rarFile.length() - 4) + EXCEPTIONS_FILE); } String archiveFile; int sep = rarFile.lastIndexOf(File.separator); if (sep > 0) archiveFile = rarFile.substring(sep + 1); else archiveFile = rarFile; out.println("Archive:\t" + archiveFile); String version; String type = ""; ResourceAdapter ra = connector.getResourceadapter(); boolean reauth = false; if (connector.getVersion() == Version.V_10) { version = "1.0"; type = "OutBound"; reauth = ra.getOutboundResourceadapter().getReauthenticationSupport(); } else { if (connector.getVersion() == Version.V_15) version = "1.5"; else if (connector.getVersion() == Version.V_16) version = "1.6"; else version = "1.7"; if (ra.getOutboundResourceadapter() != null) { reauth = ra.getOutboundResourceadapter().getReauthenticationSupport(); if (ra.getInboundResourceadapter() != null && ra.getInboundResourceadapter().getMessageadapter() != null && ra.getInboundResourceadapter().getMessageadapter().getMessagelisteners() != null && ra.getInboundResourceadapter().getMessageadapter().getMessagelisteners().size() > 0) type = "Bidirectional"; else type = "OutBound"; } else { if (ra.getInboundResourceadapter() != null) type = "InBound"; else { out.println("Rar file has problem"); return ERROR; } } } out.println("JCA version:\t" + version); out.println("Type:\t\t" + type); if (type.equals("Bidirectional") || type.equals("OutBound")) { if (ra.getOutboundResourceadapter() != null) { out.println("Transaction:\t" + ra.getOutboundResourceadapter().getTransactionSupport()); } } out.print("Reauth:\t\t"); if (reauth) out.println("Yes"); else out.println("No"); int systemExitCode = Validation.validate(new File(rarFile).toURI().toURL(), ".", cps); String compliant; if (systemExitCode == SUCCESS) compliant = "Yes"; else compliant = "No"; out.println("Compliant:\t" + compliant); out.print("Native:\t\t"); if (existNativeFile) out.println("Yes"); else out.println("No"); if (cps != null) { out.print("Extra Classpath: "); out.println(Arrays.toString(cps).replaceAll("\\[|\\]", "")); } Collections.sort(names); out.println(); out.println("Structure:"); out.println("----------"); for (String name : names) { out.println(name); } String mcfClassName = ""; Map<String, String> raConfigProperties = null; TransactionSupportEnum transSupport = TransactionSupportEnum.NoTransaction; List<AdminObject> adminObjects = null; List<ConnectionDefinition> connDefs = null; SecurityImpl secImpl = new SecurityImpl("", null); //, "", true); PoolImpl poolImpl = new PoolImpl(Defaults.TYPE, Defaults.JANITOR, Defaults.MIN_POOL_SIZE, Defaults.INITIAL_POOL_SIZE, Defaults.MAX_POOL_SIZE, Defaults.PREFILL, Defaults.FLUSH_STRATEGY, null, null); XaPoolImpl xaPoolImpl = new XaPoolImpl(Defaults.TYPE, Defaults.JANITOR, Defaults.MIN_POOL_SIZE, Defaults.INITIAL_POOL_SIZE, Defaults.MAX_POOL_SIZE, Defaults.PREFILL, Defaults.FLUSH_STRATEGY, null, Defaults.IS_SAME_RM_OVERRIDE, Defaults.PAD_XID, Defaults.WRAP_XA_RESOURCE, null); Map<String, String> introspected; if (ra.getResourceadapterClass() != null && !ra.getResourceadapterClass().equals("")) { out.println(); out.println("Resource-adapter:"); out.println("-----------------"); out.println("Class: " + ra.getResourceadapterClass()); introspected = getIntrospectedProperties(ra.getResourceadapterClass(), cl, error); if (ra.getConfigProperties() != null) { raConfigProperties = new HashMap<>(); for (ConfigProperty cp : ra.getConfigProperties()) { raConfigProperties.put(getValueString(cp.getConfigPropertyName()), getValueString(cp.getConfigPropertyValue())); removeIntrospectedValue(introspected, getValueString(cp.getConfigPropertyName())); out.println(" Config-property: " + getValueString(cp.getConfigPropertyName()) + " (" + getValueString(cp.getConfigPropertyType()) + ")"); } } if (introspected != null && !introspected.isEmpty()) { for (Map.Entry<String, String> entry : introspected.entrySet()) { out.println(" Introspected Config-property: " + entry.getKey() + " (" + entry.getValue() + ")"); } } if (introspected == null) { out.println(" ConfigProperty:"); out.println(" Unknown"); } } int line = 0; Set<String> sameClassnameSet = new HashSet<String>(); boolean needPrint = true; if (ra.getOutboundResourceadapter() != null) { out.println(); out.println("Managed-connection-factory:"); out.println("---------------------------"); if (ra.getOutboundResourceadapter().getConnectionDefinitions() != null) connDefs = new ArrayList<ConnectionDefinition>(); transSupport = ra.getOutboundResourceadapter().getTransactionSupport(); for (org.ironjacamar.common.api.metadata.spec.ConnectionDefinition mcf : ra.getOutboundResourceadapter().getConnectionDefinitions()) { mcfClassName = getValueString(mcf.getManagedConnectionFactoryClass()); if (!sameClassnameSet.contains(mcfClassName)) { sameClassnameSet.add(mcfClassName); if (line != 0) { out.println(); } line++; out.println("Class: " + mcfClassName); needPrint = true; } else { needPrint = false; } if (needPrint) { //ValidatingManagedConnectionFactory hasValidatingMcfInterface(out, error, mcfClassName, cl); //ResourceAdapterAssociation hasResourceAdapterAssociation(out, error, mcfClassName, cl); //ManagedConnectionFactory implements javax.resource.spi.TransactionSupport hasMcfTransactionSupport(out, error, mcfClassName, cl); //DissociatableManagedConnection hasDissociatableMcInterface(out, error, mcfClassName, cl, mcf.getConfigProperties()); //LazyEnlistableManagedConnection hasEnlistableMcInterface(out, error, mcfClassName, cl, mcf.getConfigProperties()); //CCI printCCIInfo(mcf, mcfClassName, cl, out, error); } Map<String, String> configProperty = null; if (mcf.getConfigProperties() != null) configProperty = new HashMap<String, String>(); introspected = getIntrospectedProperties(mcfClassName, cl, error); for (ConfigProperty cp : mcf.getConfigProperties()) { configProperty.put(getValueString(cp.getConfigPropertyName()), getValueString(cp.getConfigPropertyValue())); removeIntrospectedValue(introspected, getValueString(cp.getConfigPropertyName())); if (needPrint) out.println(" Config-property: " + getValueString(cp.getConfigPropertyName()) + " (" + getValueString(cp.getConfigPropertyType()) + ")"); } if (introspected != null && !introspected.isEmpty()) { for (Map.Entry<String, String> entry : introspected.entrySet()) { if (needPrint) out.println(" Introspected Config-property: " + entry.getKey() + " (" + entry.getValue() + ")"); } } if (introspected == null) { out.println(" ConfigProperty:"); out.println(" Unknown"); } String poolName = getValueString(mcf.getConnectionInterface()).substring( getValueString(mcf.getConnectionInterface()).lastIndexOf('.') + 1); Pool pool = null; ConnectionDefinitionImpl connImpl; if (transSupport.equals(TransactionSupportEnum.XATransaction)) { pool = xaPoolImpl; Recovery recovery = new RecoveryImpl(new CredentialImpl("domain", null), null, false, null); connImpl = new ConnectionDefinitionImpl(configProperty, mcfClassName, "java:jboss/eis/" + poolName, poolName, Defaults.ENABLED, Defaults.USE_CCM, Defaults.SHARABLE, Defaults.ENLISTMENT, Defaults.CONNECTABLE, Defaults.TRACKING, pool, null, null, secImpl, recovery, Boolean.TRUE, null); } else { pool = poolImpl; connImpl = new ConnectionDefinitionImpl(configProperty, mcfClassName, "java:jboss/eis/" + poolName, poolName, Defaults.ENABLED, Defaults.USE_CCM, Defaults.SHARABLE, Defaults.ENLISTMENT, Defaults.CONNECTABLE, Defaults.TRACKING, pool, null, null, secImpl, null, Boolean.FALSE, null); } connDefs.add(connImpl); } } line = 0; sameClassnameSet.clear(); if (ra.getAdminObjects() != null && ra.getAdminObjects().size() > 0) { out.println(); out.println("Admin-object:"); out.println("-------------"); adminObjects = new ArrayList<AdminObject>(); for (org.ironjacamar.common.api.metadata.spec.AdminObject ao : ra.getAdminObjects()) { String aoClassname = getValueString(ao.getAdminobjectClass()); if (!sameClassnameSet.contains(aoClassname)) { sameClassnameSet.add(aoClassname); if (line != 0) { out.println(); } line++; out.println("Class: " + aoClassname); //ResourceAdapterAssociation hasResourceAdapterAssociation(out, error, aoClassname, cl); out.println(" Interface: " + getValueString(ao.getAdminobjectInterface())); needPrint = true; } else { needPrint = false; } String poolName = aoClassname.substring(aoClassname.lastIndexOf('.') + 1); Map<String, String> configProperty = null; if (ao.getConfigProperties() != null) configProperty = new HashMap<String, String>(); introspected = getIntrospectedProperties(aoClassname, cl, error); for (ConfigProperty cp : ao.getConfigProperties()) { configProperty.put(getValueString(cp.getConfigPropertyName()), getValueString(cp.getConfigPropertyValue())); removeIntrospectedValue(introspected, getValueString(cp.getConfigPropertyName())); if (needPrint) out.println(" Config-property: " + getValueString(cp.getConfigPropertyName()) + " (" + getValueString(cp.getConfigPropertyType()) + ")"); } if (introspected != null && !introspected.isEmpty()) { for (Map.Entry<String, String> entry : introspected.entrySet()) { if (needPrint) out.println(" Introspected Config-property: " + entry.getKey() + " (" + entry.getValue() + ")"); } } if (introspected == null) { out.println(" ConfigProperty:"); out.println(" Unknown"); } AdminObjectImpl aoImpl = new AdminObjectImpl(configProperty, aoClassname, "java:jboss/eis/ao/" + poolName, poolName, Defaults.ENABLED, null); adminObjects.add(aoImpl); } } line = 0; sameClassnameSet.clear(); if (ra.getInboundResourceadapter() != null && ra.getInboundResourceadapter().getMessageadapter() != null && ra.getInboundResourceadapter().getMessageadapter().getMessagelisteners() != null && ra.getInboundResourceadapter().getMessageadapter().getMessagelisteners().size() > 0) { out.println(); out.println("Activation-spec:"); out.println("----------------"); for (MessageListener ml : ra.getInboundResourceadapter().getMessageadapter().getMessagelisteners()) { String asClassname = getValueString(ml.getActivationspec().getActivationspecClass()); if (!sameClassnameSet.contains(asClassname)) { sameClassnameSet.add(asClassname); if (line != 0) { out.println(); } line++; out.println("Class: " + asClassname); out.println(" Message-listener: " + getValueString(ml.getMessagelistenerType())); introspected = getIntrospectedProperties(asClassname, cl, error); if (ml.getActivationspec() != null && ml.getActivationspec().getRequiredConfigProperties() != null) { for (RequiredConfigProperty cp : ml.getActivationspec().getRequiredConfigProperties()) { removeIntrospectedValue(introspected, getValueString(cp.getConfigPropertyName())); out.println(" Required-config-property: " + getValueString(cp.getConfigPropertyName())); } } if (introspected != null && !introspected.isEmpty()) { for (Map.Entry<String, String> entry : introspected.entrySet()) { out.println(" Introspected Config-property: " + entry.getKey() + " (" + entry.getValue() + ")"); } } if (introspected == null) { out.println(" ConfigProperty:"); out.println(" Unknown"); } } } } RaImpl raImpl = new RaImpl(archiveFile, transSupport, connDefs, adminObjects, raConfigProperties); raImpl.buildResourceAdapterImpl(); outputManifest("META-INF/MANIFEST.MF", out); outputXmlDesc(xmls, out); outputRaDesc(raImpl, out); } catch (Throwable t) { System.err.println("Error: " + t.getMessage()); t.printStackTrace(error); return ERROR; } finally { if (out != null) { try { out.close(); } catch (Exception ioe) { // Ignore } } if (cl != null) { try { cl.close(); } catch (Exception ioe) { // Ignore } } if (zipFile != null) { try { zipFile.close(); } catch (Exception ioe) { // Ignore } } cleanupTempFiles(); } return SUCCESS; } private static void outputMethodInfo(PrintStream out, Class<?> clazz, URLClassLoader cl) throws ClassNotFoundException { Method[] methods = clazz.getMethods(); for (Method method : methods) { // Output return type, method name, parameters, exceptions out.print(" " + singleName(method.getReturnType().getCanonicalName()) + " " + method.getName() + "("); Class<?>[] params = method.getParameterTypes(); for (int i = 0; i < params.length; i++) { out.print(singleName(params[i].getCanonicalName())); if (i + 1 < params.length) out.print(", "); } out.print(") "); Class<?>[] exceptions = method.getExceptionTypes(); if (exceptions.length > 0) { out.print("throws "); for (int i = 0; i < exceptions.length; i++) { out.print(singleName(exceptions[i].getCanonicalName())); if (i + 1 < exceptions.length) out.print(", "); } } out.println(); } } private static String singleName(String className) { int lastPos = className.lastIndexOf("."); if (lastPos < 0) return className; else return className.substring(lastPos + 1); } /** * hasValidatingMcfInterface * * @param out output stream * @param classname classname * @param cl classloader */ private static void hasValidatingMcfInterface(PrintStream out, PrintStream error, String classname, URLClassLoader cl) { try { out.print(" Validating: "); Class<?> clazz = Class.forName(classname, true, cl); if (hasInterface(clazz, "javax.resource.spi.ValidatingManagedConnectionFactory")) { out.println("Yes"); } else { out.println("No"); } } catch (Throwable t) { // Nothing we can do t.printStackTrace(error); out.println("Unknown"); } } /** * hasResourceAdapterAssociation * * @param out output stream * @param error output stream * @param classname classname * @param cl classloader */ private static void hasResourceAdapterAssociation(PrintStream out, PrintStream error, String classname, URLClassLoader cl) { try { out.print(" Association: "); Class<?> clazz = Class.forName(classname, true, cl); if (hasInterface(clazz, "javax.resource.spi.ResourceAdapterAssociation")) { out.println("Yes"); } else { out.println("No"); } } catch (Throwable t) { // Nothing we can do t.printStackTrace(error); out.println("Unknown"); } } /** * hasMcfTransactionSupport * * @param out output stream * @param error output stream * @param classname classname * @param cl classloader */ private static void hasMcfTransactionSupport(PrintStream out, PrintStream error, String classname, URLClassLoader cl) { try { out.print(" TransactionSupport: "); Class<?> mcfClz = Class.forName(classname, true, cl); ManagedConnectionFactory mcf = (ManagedConnectionFactory)mcfClz.newInstance(); if (hasInterface(mcf.getClass(), "javax.resource.spi.TransactionSupport")) { out.println("Yes"); } else { out.println("No"); } } catch (Throwable t) { // Nothing we can do t.printStackTrace(error); out.println("Unknown"); } } private static void hasDissociatableMcInterface(PrintStream out, PrintStream error, String classname, URLClassLoader cl, List<? extends ConfigProperty> listConfProp) { hasMcInterface(out, error, classname, cl, listConfProp, "DissociatableManagedConnection", "Sharable"); } private static void hasEnlistableMcInterface(PrintStream out, PrintStream error, String classname, URLClassLoader cl, List<? extends ConfigProperty> listConfProp) { hasMcInterface(out, error, classname, cl, listConfProp, "LazyEnlistableManagedConnection", "Enlistment"); } private static void hasMcInterface(PrintStream out, PrintStream error, String classname, URLClassLoader cl, List<? extends ConfigProperty> listConfProp, String mcClassName, String tip) { ManagedConnection mcClz = null; try { out.print(" " + tip + ": "); Class<?> mcfClz = Class.forName(classname, true, cl); ManagedConnectionFactory mcf = (ManagedConnectionFactory)mcfClz.newInstance(); Injection injector = new Injection(); for (ConfigProperty cp : listConfProp) { if (!XsdString.isNull(cp.getConfigPropertyValue())) { injector.inject(mcf, cp.getConfigPropertyName().getValue(), cp.getConfigPropertyValue().getValue(), cp.getConfigPropertyType().getValue()); } } if (hasInterface(mcClz.getClass(), "javax.resource.spi." + mcClassName)) { out.println("Yes"); } else { out.println("No"); } } catch (Throwable t) { // Nothing we can do t.printStackTrace(error); out.println("Unknown"); } finally { if (mcClz != null) { try { mcClz.destroy(); } catch (ResourceException e) { e.printStackTrace(); } } } } private static void outputManifest(String manifestFile, PrintStream out) throws FileNotFoundException, IOException { outToFile(manifestFile, out); } private static void outputXmlDesc(ArrayList<String> xmls, PrintStream out) throws FileNotFoundException, IOException { for (String xmlfile : xmls) { /*out.println(); out.println(xmlfile + ":"); for (int i = 0; i <= xmlfile.length(); i++) { out.print("-"); } out.println();*/ outToFile(xmlfile, out); } } private static void outToFile(String fileName, PrintStream out) throws IOException { Reader in = null; try { in = new FileReader(root.getAbsolutePath() + File.separator + fileName); out.println(); out.println(fileName + ":"); for (int i = 0; i <= fileName.length(); i++) { out.print("-"); } out.println(); char[] buffer = new char[4096]; for (;;) { int nBytes = in.read(buffer); if (nBytes <= 0) break; for (int i = 0; i < nBytes; i++) { if (buffer[i] != 13) out.print(buffer[i]); } } out.flush(); } catch (FileNotFoundException e) { // ignore } finally { try { if (in != null) in.close(); } catch (IOException ignore) { // Ignore } } } private static void printCCIInfo(org.ironjacamar.common.api.metadata.spec.ConnectionDefinition connectionDefinition, String mcfClassName, URLClassLoader cl, PrintStream out, PrintStream error) { Class<?> cfiClazz = null; Class<?> ciClazz = null; String cci = "No"; String cfi = getValueString(connectionDefinition.getConnectionFactoryInterface()); String ci = getValueString(connectionDefinition.getConnectionInterface()); if ("javax.resource.cci.ConnectionFactory".equals(cfi)) cci = "Yes"; out.print(" CCI: "); out.println(cci); out.println(" ConnectionFactory (" + cfi + ")"); try { cfiClazz = Class.forName(cfi, true, cl); outputMethodInfo(out, cfiClazz, cl); } catch (Throwable t) { out.println(" Unknown"); t.printStackTrace(error); } try { out.println(" Connection (" + ci + ")"); ciClazz = Class.forName(ci, true, cl); outputMethodInfo(out, ciClazz, cl); } catch (Throwable t) { out.println(" Unknown"); t.printStackTrace(error); } } /** * Output Resource Adapter XML description * * @param raImpl RaImpl * @param out PrintStream * @throws ParserConfigurationException * @throws SAXException * @throws IOException * @throws TransformerFactoryConfigurationError * @throws TransformerConfigurationException * @throws TransformerException */ private static void outputRaDesc(RaImpl raImpl, PrintStream out) throws ParserConfigurationException, SAXException, IOException, TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException { String raString = "<resource-adapters>" + raImpl.toString() + "</resource-adapters>"; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(new StringReader(raString))); out.println(); out.println("Deployment descriptor:"); out.println("----------------------"); TransformerFactory tfactory = TransformerFactory.newInstance(); Transformer serializer; serializer = tfactory.newTransformer(); //Setup indenting to "pretty print" serializer.setOutputProperty(OutputKeys.INDENT, "yes"); serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); serializer.transform(new DOMSource(doc), new StreamResult(out)); } /** * Should the archive be scanned for annotations * @param cmd The metadata * @return True if scan is needed; otherwise false */ private static boolean scanArchive(Connector cmd) { if (cmd == null) return true; if (cmd.getVersion() == Version.V_16 || cmd.getVersion() == Version.V_17) { if (!cmd.isMetadataComplete()) return true; } return false; } private static File getRoot(String rarFile) { if (rarFile == null) throw new IllegalArgumentException("Rar file name is null"); try { File f = new File(rarFile); if (f.isFile()) { File destination = new File(tempdir, subdir); return extract(f, destination); } else { return f; } } catch (Throwable t) { // Nothing we can do } return null; } private static URLClassLoader loadClass(String[] classpath) { try { // Create classloader URL[] allurls; URL[] urls = getUrls(root); if (classpath != null && classpath.length > 0) { List<URL> listUrl = new ArrayList<URL>(); for (URL u : urls) listUrl.add(u); for (String jar : classpath) { if (jar.endsWith(".jar")) listUrl.add(new File(jar).toURI().toURL()); } allurls = listUrl.toArray(new URL[listUrl.size()]); } else allurls = urls; URLClassLoader cl = SecurityActions.createURLCLassLoader(allurls, SecurityActions.getThreadContextClassLoader()); return cl; } catch (Throwable t) { // Nothing we can do } return null; } private static void cleanupTempFiles() { File destination = new File(tempdir, subdir); if (destination.exists()) { try { recursiveDelete(destination); } catch (IOException ioe) { // Ignore } } } private static boolean hasInterface(Class<?> clazz, String interfaceName) { for (Class<?> iface : getAllInterfaces(clazz)) { if (iface.getName().equals(interfaceName)) { return true; } } return false; } private static List<Class<?>> getAllInterfaces(Class<?> cls) { if (cls == null) { return null; } LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<Class<?>>(); getAllInterfaces(cls, interfacesFound); return new ArrayList<Class<?>>(interfacesFound); } private static void getAllInterfaces(Class<?> cls, HashSet<Class<?>> interfacesFound) { while (cls != null) { Class<?>[] interfaces = cls.getInterfaces(); for (Class<?> i : interfaces) { if (interfacesFound.add(i)) { getAllInterfaces(i, interfacesFound); } } cls = cls.getSuperclass(); } } /** * Get the introspected properties for a class * @param clz The fully qualified class name * @param cl classloader * @return The properties (name, type) */ private static Map<String, String> getIntrospectedProperties(String clz, URLClassLoader cl, PrintStream error) { Map<String, String> result = null; try { Class<?> c = Class.forName(clz, true, cl); result = new TreeMap<String, String>(); Method[] methods = c.getMethods(); for (Method m : methods) { if (m.getName().startsWith("set") && m.getParameterTypes().length == 1 && isValidType(m.getParameterTypes()[0])) { String name = m.getName().substring(3); if (name.length() == 1) { name = name.toLowerCase(Locale.US); } else { name = name.substring(0, 1).toLowerCase(Locale.US) + name.substring(1); } String type = m.getParameterTypes()[0].getName(); result.put(name, type); } } } catch (Throwable t) { // Nothing we can do t.printStackTrace(error); } return result; } /** * Is valid type * @param type The type * @return True if valid; otherwise false */ private static boolean isValidType(Class<?> type) { return validTypes.contains(type); } /** * Remove introspected value * @param m The map * @param name The name */ private static void removeIntrospectedValue(Map<String, String> m, String name) { if (m != null) { m.remove(name); if (name.length() == 1) { name = name.toUpperCase(Locale.US); } else { name = name.substring(0, 1).toUpperCase(Locale.US) + name.substring(1); } m.remove(name); if (name.length() == 1) { name = name.toLowerCase(Locale.US); } else { name = name.substring(0, 1).toLowerCase(Locale.US) + name.substring(1); } m.remove(name); } } /** * Get the URLs for the directory and all libraries located in the directory * @param directory The directory * @return The URLs * @exception MalformedURLException MalformedURLException * @exception IOException IOException */ private static URL[] getUrls(File directory) throws MalformedURLException, IOException { List<URL> list = new LinkedList<URL>(); if (directory.exists() && directory.isDirectory()) { // Add directory list.add(directory.toURI().toURL()); // Add the contents of the directory too File[] jars = directory.listFiles(new FilenameFilter() { /** * Accept * @param dir The directory * @param name The name * @return True if accepts; otherwise false */ public boolean accept(File dir, String name) { return name.endsWith(".jar"); } }); if (jars != null) { for (int j = 0; j < jars.length; j++) { list.add(jars[j].getCanonicalFile().toURI().toURL()); } } } return list.toArray(new URL[list.size()]); } /** * Extract a JAR type file * @param file The file * @param directory The directory where the file should be extracted * @return The root of the extracted JAR file * @exception IOException Thrown if an error occurs */ private static File extract(File file, File directory) throws IOException { if (file == null) throw new IllegalArgumentException("File is null"); if (directory == null) throw new IllegalArgumentException("Directory is null"); File target = new File(directory, file.getName()); if (target.exists()) recursiveDelete(target); if (!target.mkdirs()) throw new IOException("Could not create " + target); JarFile jar = null; try { jar = new JarFile(file); Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry je = entries.nextElement(); File copy = new File(target, je.getName()); if (!je.isDirectory()) { InputStream in = null; OutputStream out = null; // Make sure that the directory is _really_ there if (copy.getParentFile() != null && !copy.getParentFile().exists()) { if (!copy.getParentFile().mkdirs()) throw new IOException("Could not create " + copy.getParentFile()); } try { in = new BufferedInputStream(jar.getInputStream(je)); out = new BufferedOutputStream(new FileOutputStream(copy)); byte[] buffer = new byte[4096]; for (;;) { int nBytes = in.read(buffer); if (nBytes <= 0) break; out.write(buffer, 0, nBytes); } out.flush(); } finally { try { if (out != null) out.close(); } catch (IOException ignore) { // Ignore } try { if (in != null) { in.close(); } } catch (IOException ignore) { // Ignore } } } else { if (!copy.exists()) { if (!copy.mkdirs()) throw new IOException("Could not create " + copy); } else { if (!copy.isDirectory()) throw new IOException(copy + " isn't a directory"); } } } } finally { try { if (jar != null) jar.close(); } catch (IOException ignore) { // Ignore } } return target; } /** * Recursive delete * @param f The file handler * @exception IOException Thrown if a file could not be deleted */ private static void recursiveDelete(File f) throws IOException { if (f != null && f.exists()) { File[] files = f.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { recursiveDelete(files[i]); } else { if (!files[i].delete()) throw new IOException("Could not delete " + files[i]); } } } if (!f.delete()) throw new IOException("Could not delete " + f); } } /** * get correct value string * @param value xsdstring * @return correct string */ private static String getValueString(XsdString value) { if (value == null || value == XsdString.NULL_XSDSTRING) return ""; else return value.getValue(); } /** * Tool usage */ private static void usage() { System.out.println("Usage: ./rar-info.sh [-classpath <lib>[:<lib>]*] [--stdout] [-o <reportFile>] <file>"); } }