public void process(File f) throws Exception { if (f.isDirectory()) { File[] files = f.listFiles( new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.matches(FILE_PATTERN); } }); for (File ff : files) { byte[] bindingBytes = Files.toByteArray(ff); this.addCurrentBinding(bindingBytes, ff.getName(), "file:" + ff.getAbsolutePath()); } } else { String digest = new BigInteger(Files.getDigest(f, Digest.MD5.get())).abs().toString(16); CURRENT_PROPS.put(BINDING_CACHE_JAR_PREFIX + f.getName(), digest); final JarFile jar = new JarFile(f); final List<JarEntry> jarList = Collections.list(jar.entries()); for (final JarEntry j : jarList) { try { if (j.getName().matches(FILE_PATTERN)) { byte[] bindingBytes = ByteStreams.toByteArray(jar.getInputStream(j)); String bindingName = j.getName(); String bindingFullPath = "jar:file:" + f.getAbsolutePath() + "!/" + bindingName; this.addCurrentBinding(bindingBytes, bindingName, bindingFullPath); } else if (j.getName().matches(".*\\.class.{0,1}")) { final String classGuess = j.getName().replaceAll("/", ".").replaceAll("\\.class.{0,1}", ""); final Class candidate = ClassLoader.getSystemClassLoader().loadClass(classGuess); if (MSG_BASE_CLASS.isAssignableFrom(candidate) || MSG_DATA_CLASS.isAssignableFrom(candidate)) { InputSupplier<InputStream> classSupplier = Resources.newInputStreamSupplier(ClassLoader.getSystemResource(j.getName())); File destClassFile = SubDirectory.CLASSCACHE.getChildFile(j.getName()); if (!destClassFile.exists()) { Files.createParentDirs(destClassFile); Files.copy(classSupplier, destClassFile); Logs.extreme() .debug("Caching: " + j.getName() + " => " + destClassFile.getAbsolutePath()); } BINDING_CLASS_MAP.putIfAbsent(classGuess, candidate); } } } catch (RuntimeException ex) { LOG.error(ex, ex); jar.close(); throw ex; } } jar.close(); } }
enum BindingFileSearch implements Predicate<URI> { INSTANCE; private static final String BINDING_EMPTY = "<binding>\n</binding>"; private static final Boolean BINDING_DEBUG = System.getProperty("euca.binding.debug") != null; private static final Boolean BINDING_DEBUG_EXTREME = System.getProperty("euca.binding.debug.extreme") != null; private static List<URI> BINDING_LIST = Lists.newArrayList(); private static ConcurrentMap<String, Class> BINDING_CLASS_MAP = Maps.newConcurrentMap(); private static final String BINDING_CACHE_JAR_PREFIX = "jar."; private static final String BINDING_CACHE_BINDING_PREFIX = "binding."; private static final String BINDING_CACHE_DIGEST_LIST = "classcache.properties"; private static final File CACHE_LIST = SubDirectory.CLASSCACHE.getChildFile(BINDING_CACHE_DIGEST_LIST); private final ClassLoader CACHE_CLASS_LOADER; private final Class<?> MSG_BASE_CLASS; private final Class<?> MSG_DATA_CLASS; private static final String FILE_PATTERN = System.getProperty("euca.binding.pattern", ".*\\-binding.xml"); private static final Properties CURRENT_PROPS = new Properties(); private BindingFileSearch() { try { CACHE_CLASS_LOADER = new URLClassLoader(new URL[] {SubDirectory.CLASSCACHE.getFile().toURL()}); MSG_BASE_CLASS = Class.forName("edu.ucsb.eucalyptus.msgs.BaseMessage"); MSG_DATA_CLASS = Class.forName("edu.ucsb.eucalyptus.msgs.EucalyptusData"); } catch (Exception ex) { LOG.error(ex, ex); throw Exceptions.toUndeclared(ex); } } public boolean check() { final Properties oldProps = new Properties(); if (BindingFileSearch.CACHE_LIST.exists()) { try { Reader propIn = Files.newReader(BindingFileSearch.CACHE_LIST, Charset.defaultCharset()); oldProps.load(propIn); } catch (Exception ex) { LOG.debug(ex, ex); } } Map<String, String> oldBindings = Maps.fromProperties(oldProps); Map<String, String> newBindings = Maps.fromProperties(BindingFileSearch.CURRENT_PROPS); if (oldBindings.equals(newBindings)) { LOG.info("Found up-to-date binding class cache: skipping message binding."); return true; } else { MapDifference<String, String> diffBindings = Maps.difference(oldBindings, newBindings); LOG.info("Binding class cache expired (old,new): \n" + diffBindings.entriesDiffering()); try { Files.deleteRecursively(SubDirectory.CLASSCACHE.getFile()); } catch (IOException ex) { LOG.error(ex, ex); } SubDirectory.CLASSCACHE.getFile().mkdir(); return false; } } public void store() throws IOException { Writer propOut = new FileWriter(CACHE_LIST); try { try { CURRENT_PROPS.store(propOut, "Binding class cache generated on: "); propOut.close(); } catch (Exception ex) { LOG.error(ex, ex); propOut.close(); } } catch (IOException ex) { for (File f : SubDirectory.CLASSCACHE.getFile().listFiles()) { try { LOG.info("Cleaning up class cache: " + f.getCanonicalPath()); Files.deleteRecursively(f); } catch (IOException ex1) { LOG.error(ex1, ex1); } } throw ex; } } public void process(File f) throws Exception { if (f.isDirectory()) { File[] files = f.listFiles( new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.matches(FILE_PATTERN); } }); for (File ff : files) { byte[] bindingBytes = Files.toByteArray(ff); this.addCurrentBinding(bindingBytes, ff.getName(), "file:" + ff.getAbsolutePath()); } } else { String digest = new BigInteger(Files.getDigest(f, Digest.MD5.get())).abs().toString(16); CURRENT_PROPS.put(BINDING_CACHE_JAR_PREFIX + f.getName(), digest); final JarFile jar = new JarFile(f); final List<JarEntry> jarList = Collections.list(jar.entries()); for (final JarEntry j : jarList) { try { if (j.getName().matches(FILE_PATTERN)) { byte[] bindingBytes = ByteStreams.toByteArray(jar.getInputStream(j)); String bindingName = j.getName(); String bindingFullPath = "jar:file:" + f.getAbsolutePath() + "!/" + bindingName; this.addCurrentBinding(bindingBytes, bindingName, bindingFullPath); } else if (j.getName().matches(".*\\.class.{0,1}")) { final String classGuess = j.getName().replaceAll("/", ".").replaceAll("\\.class.{0,1}", ""); final Class candidate = ClassLoader.getSystemClassLoader().loadClass(classGuess); if (MSG_BASE_CLASS.isAssignableFrom(candidate) || MSG_DATA_CLASS.isAssignableFrom(candidate)) { InputSupplier<InputStream> classSupplier = Resources.newInputStreamSupplier(ClassLoader.getSystemResource(j.getName())); File destClassFile = SubDirectory.CLASSCACHE.getChildFile(j.getName()); if (!destClassFile.exists()) { Files.createParentDirs(destClassFile); Files.copy(classSupplier, destClassFile); Logs.extreme() .debug("Caching: " + j.getName() + " => " + destClassFile.getAbsolutePath()); } BINDING_CLASS_MAP.putIfAbsent(classGuess, candidate); } } } catch (RuntimeException ex) { LOG.error(ex, ex); jar.close(); throw ex; } } jar.close(); } } private void addCurrentBinding( byte[] bindingBytes, String bindingName, String bindingFullPath) { LOG.debug("Binding cache: loading binding from: " + bindingFullPath); BINDING_LIST.add(URI.create(bindingFullPath)); String digest = new BigInteger(Digest.MD5.get().digest(bindingBytes)).abs().toString(16); String entryName = BINDING_CACHE_BINDING_PREFIX + bindingName; if (!CURRENT_PROPS.containsKey(entryName)) { CURRENT_PROPS.put(entryName, digest); } else { // TODO:GRZE finish up this case. LOG.info("Duplicate binding entry: " + CURRENT_PROPS.getProperty(entryName)); } } @Override public boolean apply(URI input) { try { String shortPath = input.toURL().getPath().replaceAll(".*!/", ""); String sname = Utility.bindingFromFileName(shortPath); // BindingDefinition def = Utility.loadBinding( input.toASCIIString( ), sname, // input.toURL( ).openStream( ), input.toURL( ), true ); ValidationContext vctx = BindingElement.newValidationContext(); BindingElement root = BindingElement.validateBinding( input.toASCIIString(), input.toURL(), input.toURL().openStream(), vctx); Predicate<BindingElement> writeFile = new Predicate<BindingElement>() { @SuppressWarnings("unchecked") @Override public boolean apply(BindingElement input) { for (ElementBase child : (List<ElementBase>) input.topChildren()) { try { if (child instanceof MappingElement) { MappingElementBase mapping = (MappingElementBase) child; ClassFile classFile = mapping.getHandledClass().getClassFile(); String classFileName = classFile.getName().replace(".", "/") + ".class"; InputSupplier<InputStream> classSupplier = Resources.newInputStreamSupplier( ClassLoader.getSystemResource(classFileName)); File destClassFile = SubDirectory.CLASSCACHE.getChildFile(classFileName); if (!destClassFile.exists()) { Files.createParentDirs(destClassFile); Files.copy(classSupplier, destClassFile); } ClassFile cf = ClassFile.getClassFile(classFile.getName()); Logs.extreme() .debug( "Caching: " + classFile.getName() + " => " + destClassFile.getAbsolutePath()); } else if (child instanceof IncludeElement) { IncludeElement includeElement = (IncludeElement) child; BindingElement bind = includeElement.getBinding(); if (bind != null) { this.apply(bind); } else { Files.write( BINDING_EMPTY.getBytes(), SubDirectory.CLASSCACHE.getChildFile( includeElement.getIncludePath().replace("classpath:", ""))); } } } catch (Exception ex) { LOG.error(ex, ex); } } return true; } }; if (!writeFile.apply(root)) { writeFile.apply(root); } return true; } catch (Exception ex) { throw Exceptions.toUndeclared(ex); } } public static void compile() { LOG.info("Binding cache: processing message and binding files."); processFiles(); if (BindingFileSearch.INSTANCE.check()) { LOG.info("Binding cache: nothing to do."); } else { LOG.info("Binding cache: regenerating cache."); try { LOG.info("Binding cache: generating internal bindings."); // generate msgs-binding InternalSoapBindingGenerator gen = new InternalSoapBindingGenerator(); for (Class genBindClass : BindingFileSearch.BINDING_CLASS_MAP.values()) { Logs.extreme().debug("Generating binding: " + genBindClass); gen.processClass(genBindClass); } gen.close(); BINDING_LIST.add(gen.getOutFile().toURI()); LOG.info("Binding cache: populating cache from transitive closure of bindings."); // load *-binding.xml, populate cache w/ all referenced files BindingFileSearch.reset(Utility.getClassPaths()); Iterables.all(BindingFileSearch.BINDING_LIST, BindingFileSearch.INSTANCE); BindingFileSearch.reset(Utility.getClassPaths()); LOG.info("Binding cache: loading and validating bindings."); Map<URI, BindingDefinition> bindingDefs = Maps.newHashMap(); PrintStream oldOut = System.out, oldErr = System.err; for (URI binding : BINDING_LIST) { String shortPath = binding.toURL().getPath().replaceAll(".*!/", ""); String sname = Utility.bindingFromFileName(shortPath); BindingDefinition def = Utility.loadBinding( binding.toASCIIString(), sname, binding.toURL().openStream(), binding.toURL(), true); bindingDefs.put(binding, def); def.print(); } LOG.info("Binding cache: compiling bindings."); for (Entry<URI, BindingDefinition> def : bindingDefs.entrySet()) { try { LOG.debug("Binding cache: " + def.getKey()); def.getValue() .generateCode( BindingFileSearch.BINDING_DEBUG, BindingFileSearch.BINDING_DEBUG_EXTREME); } catch (RuntimeException e) { throw new JiBXException( "\n*** Error during code generation for file '" + def.getKey() + "' -\n this may be due to an error in " + "your binding or classpath, or to an error in the " + "JiBX code ***\n", e); } } ClassFile[][] lists = MungedClass.fixDispositions(); for (BindingDefinition def : bindingDefs.values()) { def.addClassList(lists[0], lists[1]); } MungedClass.writeChanges(); LOG.info("Binding cache: wrote " + lists[0].length + " files"); LOG.info("Binding cache: kept " + lists[1].length + " files unchanged:"); LOG.info("Binding cache: deleted " + lists[2].length + " files:"); BindingFileSearch.INSTANCE.store(); System.exit(123); // success! now we restart. } catch (Exception ex) { LOG.error(ex, ex); System.exit(1); throw new Error( "Failed to prepare the system while trying to compile bindings: " + ex.getMessage(), ex); } } } public static void processFiles() { final File libDir = new File(BaseDirectory.LIB.toString()); for (final File f : libDir.listFiles()) { if (f.getName().startsWith("eucalyptus") && f.getName().endsWith(".jar") && !f.getName().matches(".*-ext-.*")) { EventRecord.here( ServiceJarDiscovery.class, EventType.BOOTSTRAP_INIT_SERVICE_JAR, f.getName()) .info(); try { BindingFileSearch.INSTANCE.process(f); } catch (final Throwable e) { LOG.error(e.getMessage()); continue; } } } for (String pathName : ClassPath.SYSTEM_CLASS_PATH.getClassPath().split(File.pathSeparator)) { File pathFile = new File(pathName); if (pathFile.isDirectory()) { try { BindingFileSearch.INSTANCE.process(pathFile); } catch (final Throwable e) { LOG.error(e.getMessage()); continue; } ; } } } public static String[] reset(String[] paths) { ClassCache.setPaths(paths); ClassFile.setPaths(paths); ClasspathUrlExtender.setClassLoader(ClassFile.getClassLoader()); BoundClass.reset(); MungedClass.reset(); BindingDefinition.reset(); BranchWrapper.setTracking(false); BranchWrapper.setErrorOverride(false); return paths; } }