| /* |
| * 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.apache.felix.ipojo.manipulator; |
| |
| import org.apache.felix.ipojo.manipulator.manifest.FileManifestProvider; |
| import org.apache.felix.ipojo.manipulator.metadata.*; |
| import org.apache.felix.ipojo.manipulator.render.MetadataRenderer; |
| import org.apache.felix.ipojo.manipulator.reporter.SystemReporter; |
| import org.apache.felix.ipojo.manipulator.spi.ModuleProvider; |
| import org.apache.felix.ipojo.manipulator.spi.provider.ServiceLoaderModuleProvider; |
| import org.apache.felix.ipojo.manipulator.store.DirectoryResourceStore; |
| import org.apache.felix.ipojo.manipulator.store.JarFileResourceStore; |
| import org.apache.felix.ipojo.manipulator.store.builder.DefaultManifestBuilder; |
| import org.apache.felix.ipojo.manipulator.store.mapper.WABResourceMapper; |
| import org.apache.felix.ipojo.manipulator.util.Constants; |
| import org.apache.felix.ipojo.manipulator.util.Metadatas; |
| import org.apache.felix.ipojo.manipulator.util.Strings; |
| import org.apache.felix.ipojo.manipulator.visitor.check.CheckFieldConsistencyVisitor; |
| import org.apache.felix.ipojo.manipulator.visitor.writer.ManipulatedResourcesWriter; |
| import org.apache.felix.ipojo.metadata.Element; |
| import org.apache.felix.ipojo.xml.parser.SchemaResolver; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.List; |
| import java.util.jar.JarFile; |
| |
| /** |
| * Pojoization allows creating an iPOJO bundle from a "normal" bundle. |
| * |
| * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| */ |
| public class Pojoization { |
| |
| /** |
| * Flag describing if we need or not compute annotations. |
| * By default, compute the annotations. |
| */ |
| private boolean m_ignoreAnnotations; |
| |
| /** |
| * Flag describing if we need or not use local XSD files |
| * (i.e. use the {@link SchemaResolver} or not). |
| * If <code>true</code> the local XSD are used (default to {@literal false}). |
| */ |
| private boolean m_useLocalXSD = false; |
| |
| /** |
| * Reporter for error reporting. |
| */ |
| private final Reporter m_reporter; |
| |
| private final ModuleProvider m_moduleProvider; |
| |
| public Pojoization() { |
| this(new SystemReporter()); |
| } |
| |
| public Pojoization(ModuleProvider provider) { |
| this(new SystemReporter(), provider); |
| } |
| |
| public Pojoization(Reporter reporter) { |
| this(reporter, new ServiceLoaderModuleProvider()); |
| } |
| |
| public Pojoization(Reporter reporter, final ModuleProvider moduleProvider) { |
| m_reporter = reporter; |
| m_moduleProvider = moduleProvider; |
| m_reporter.info("Apache Felix iPOJO Manipulator - " + Constants.getVersion()); |
| } |
| |
| /** |
| * Activates annotation processing. |
| */ |
| public void disableAnnotationProcessing() { |
| m_ignoreAnnotations = true; |
| } |
| |
| /** |
| * Activates the entity resolver loading |
| * XSD files from the classloader. |
| */ |
| public void setUseLocalXSD() { |
| m_useLocalXSD = true; |
| } |
| |
| /** |
| * @return all the errors (fatal) reported by the manipulation process. |
| */ |
| public List<String> getErrors() { |
| // Simple delegation for backward compatibility |
| return m_reporter.getErrors(); |
| } |
| |
| /** |
| * @return all the warnings (non fatal) reported by the manipulation process. |
| */ |
| public List<String> getWarnings() { |
| // Simple delegation for backward compatibility |
| return m_reporter.getWarnings(); |
| } |
| |
| /** |
| * Manipulates an input bundle. |
| * This method creates an iPOJO bundle based on the given metadata file. |
| * The original and final bundles must be different. |
| * <p/> |
| * This method does not use the classloader parameter, and use the classloader having loaded the |
| * {@link org.apache.felix.ipojo.manipulator.Pojoization} class. It's definitely not recommended. |
| * |
| * @param in the original bundle. |
| * @param out the final bundle. |
| * @param metadata the iPOJO metadata input stream. |
| * @deprecated |
| */ |
| public void pojoization(File in, File out, InputStream metadata) { |
| pojoization(in, out, metadata, this.getClass().getClassLoader()); |
| } |
| |
| /** |
| * Manipulates an input bundle. |
| * This method creates an iPOJO bundle based on the given metadata file. |
| * The original and final bundles must be different. |
| * |
| * @param in the original bundle. |
| * @param out the final bundle. |
| * @param metadata the iPOJO metadata input stream. |
| * @param loader the classloader used to compute the bytecode frames. |
| */ |
| public void pojoization(File in, File out, InputStream metadata, ClassLoader loader) { |
| StreamMetadataProvider provider = new StreamMetadataProvider(metadata, m_reporter); |
| provider.setValidateUsingLocalSchemas(m_useLocalXSD); |
| |
| ResourceStore store; |
| try { |
| JarFile origin = new JarFile(in); |
| JarFileResourceStore jfrs = new JarFileResourceStore(origin, out); |
| jfrs.setClassLoader(loader); |
| if (in.getName().endsWith(".war")) { |
| // this is a war file, use the right mapper |
| jfrs.setResourceMapper(new WABResourceMapper()); |
| } |
| jfrs.setManifest(origin.getManifest()); |
| DefaultManifestBuilder dmb = new DefaultManifestBuilder(); |
| dmb.setMetadataRenderer(new MetadataRenderer()); |
| jfrs.setManifestBuilder(dmb); |
| store = jfrs; |
| } catch (IOException e) { |
| m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file"); |
| return; |
| } |
| |
| ManipulationVisitor visitor = createDefaultVisitorChain(store); |
| |
| pojoization(store, provider, visitor, loader); |
| } |
| |
| private ManipulationVisitor createDefaultVisitorChain(ResourceStore store) { |
| ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter(); |
| writer.setReporter(m_reporter); |
| writer.setResourceStore(store); |
| |
| CheckFieldConsistencyVisitor checkFieldConsistencyVisitor = new CheckFieldConsistencyVisitor(writer); |
| checkFieldConsistencyVisitor.setReporter(m_reporter); |
| return checkFieldConsistencyVisitor; |
| } |
| |
| /** |
| * Manipulates an input bundle. |
| * This method creates an iPOJO bundle based on the given metadata file. |
| * The original and final bundles must be different. |
| * <p/> |
| * This method does not use the classloader parameter, and use the classloader having loaded the |
| * {@link org.apache.felix.ipojo.manipulator.Pojoization} class. It's definitely not recommended. |
| * |
| * @param in the original bundle. |
| * @param out the final bundle. |
| * @param metadataFile the iPOJO metadata file (XML). |
| * @deprecated |
| */ |
| public void pojoization(File in, File out, File metadataFile) { |
| pojoization(in, out, metadataFile, this.getClass().getClassLoader()); |
| } |
| |
| /** |
| * Manipulates an input bundle. |
| * This method creates an iPOJO bundle based on the given metadata file. |
| * The original and final bundles must be different. |
| * |
| * @param in the original bundle. |
| * @param out the final bundle. |
| * @param metadataFile the iPOJO metadata file (XML). |
| * @param loader the classloader used to compute the bytecode frames. |
| */ |
| public void pojoization(File in, File out, File metadataFile, ClassLoader loader) { |
| MetadataProvider provider = new EmptyMetadataProvider(); |
| if (metadataFile != null) { |
| FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter); |
| fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD); |
| provider = fileMetadataProvider; |
| } |
| |
| ResourceStore store; |
| try { |
| JarFile origin = new JarFile(in); |
| JarFileResourceStore jfrs = new JarFileResourceStore(origin, out); |
| jfrs.setClassLoader(loader); |
| if (in.getName().endsWith(".war")) { |
| // this is a war file, use the right mapper |
| jfrs.setResourceMapper(new WABResourceMapper()); |
| } |
| jfrs.setManifest(origin.getManifest()); |
| DefaultManifestBuilder dmb = new DefaultManifestBuilder(); |
| dmb.setMetadataRenderer(new MetadataRenderer()); |
| jfrs.setManifestBuilder(dmb); |
| store = jfrs; |
| } catch (IOException e) { |
| m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file"); |
| return; |
| } |
| |
| ManipulationVisitor visitor = createDefaultVisitorChain(store); |
| |
| pojoization(store, provider, visitor, loader); |
| } |
| |
| /** |
| * Manipulates an expanded bundles. |
| * Classes are in the specified directory. |
| * this method allows to update a customized manifest. |
| * <p/> |
| * This method does not use the classloader parameter, and use the classloader having loaded the |
| * {@link org.apache.felix.ipojo.manipulator.Pojoization} class. It's definitely not recommended. |
| * |
| * @param directory the directory containing classes |
| * @param metadataFile the metadata file |
| * @param manifestFile the manifest file. <code>null</code> to use directory/META-INF/MANIFEST.mf |
| * @deprecated |
| */ |
| public void directoryPojoization(File directory, File metadataFile, File manifestFile) { |
| directoryPojoization(directory, metadataFile, manifestFile, this.getClass().getClassLoader()); |
| } |
| |
| /** |
| * Manipulates an expanded bundles. |
| * Classes are in the specified directory. |
| * this method allows to update a customized manifest. |
| * |
| * @param directory the directory containing classes |
| * @param metadataFile the metadata file |
| * @param manifestFile the manifest file. <code>null</code> to use directory/META-INF/MANIFEST.mf |
| * @param loader the classloader used to compute the bytecode frames. |
| */ |
| public void directoryPojoization(File directory, File metadataFile, File manifestFile, ClassLoader loader) { |
| // Get the metadata.xml location if not null |
| MetadataProvider provider = new EmptyMetadataProvider(); |
| if (metadataFile != null) { |
| FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter); |
| fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD); |
| provider = fileMetadataProvider; |
| } |
| |
| ManifestProvider manifestProvider; |
| File selectedManifestFile; |
| if (manifestFile != null) { |
| if (manifestFile.isFile()) { |
| try { |
| manifestProvider = new FileManifestProvider(manifestFile); |
| selectedManifestFile = manifestFile; |
| } catch (IOException e) { |
| m_reporter.error("Cannot read Manifest from '" + manifestFile.getAbsolutePath() + "'"); |
| return; |
| } |
| } else { |
| m_reporter.error("The manifest file " + manifestFile.getAbsolutePath() + " does not exist"); |
| return; |
| } |
| } else { |
| // If the manifest is not specified, the m_dir/META-INF/MANIFEST.MF is used. |
| File metaInf = new File(directory, "META-INF"); |
| File original = new File(metaInf, "MANIFEST.MF"); |
| if (original.isFile()) { |
| try { |
| manifestProvider = new FileManifestProvider(original); |
| selectedManifestFile = original; |
| } catch (IOException e) { |
| m_reporter.error("Cannot read Manifest from '" + original.getAbsolutePath() + "'"); |
| return; |
| } |
| } else { |
| m_reporter.error("The manifest file " + original.getAbsolutePath() + " does not exist"); |
| return; |
| } |
| } |
| |
| DirectoryResourceStore store; |
| if (directory.exists() && directory.isDirectory()) { |
| store = new DirectoryResourceStore(directory); |
| File webinf = new File(directory, "WEB-INF"); |
| if (directory.getName().endsWith(".war") || webinf.isDirectory()) { |
| // this is a war file, use the right mapper |
| store.setResourceMapper(new WABResourceMapper()); |
| } |
| store.setManifest(manifestProvider.getManifest()); |
| store.setManifestFile(selectedManifestFile); |
| DefaultManifestBuilder dmb = new DefaultManifestBuilder(); |
| dmb.setMetadataRenderer(new MetadataRenderer()); |
| store.setManifestBuilder(dmb); |
| } else { |
| m_reporter.error("The directory " + directory.getAbsolutePath() + " does not exist or is not a directory."); |
| return; |
| } |
| |
| ManipulationVisitor visitor = createDefaultVisitorChain(store); |
| |
| pojoization(store, provider, visitor, loader); |
| |
| } |
| |
| public void pojoization(final ResourceStore store, |
| final MetadataProvider metadata, |
| final ManipulationVisitor visitor, |
| final ClassLoader loader) { |
| |
| ManipulationEngine engine = new ManipulationEngine(loader); |
| engine.setResourceStore(store); |
| engine.setReporter(m_reporter); |
| engine.setManipulationVisitor(visitor); |
| |
| try { |
| |
| // Creates a composite to store multiple metadata providers |
| CompositeMetadataProvider composite = new CompositeMetadataProvider(m_reporter); |
| composite.addMetadataProvider(metadata); |
| |
| if (!m_ignoreAnnotations) { |
| composite.addMetadataProvider(new AnnotationMetadataProvider(store, m_moduleProvider, m_reporter)); |
| } |
| |
| // Get metadata |
| List<Element> metadatas = composite.getMetadatas(); |
| |
| // Construct ManipulationUnits |
| // And collect non-component metadata |
| for (Element meta : metadatas) { |
| String name = Metadatas.getComponentType(meta); |
| if (name != null) { |
| // Only handler and component have a classname attribute |
| String path = Strings.asResourcePath(name); |
| engine.addManipulationUnit(new ManipulationUnit(path, meta)); |
| } else { |
| visitor.visitMetadata(meta); |
| } |
| } |
| |
| } catch (IOException e) { |
| m_reporter.error("Cannot load metadata " + e.getMessage()); |
| return; |
| } |
| |
| // Start the manipulation |
| engine.generate(); |
| |
| // Tell the visitor that we have finished |
| visitor.visitEnd(); |
| |
| } |
| } |
| |