/* * JBoss, Home of Professional Open Source * Copyright 2006, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt 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 GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * 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 GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General 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.jboss.deployers.vfs.spi.deployer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.deployers.vfs.spi.structure.VFSDeploymentUnit; import org.jboss.deployers.structure.spi.DeploymentUnit; import org.jboss.virtual.VirtualFile; /** * Multiple VFS parsing deployer. * * @param <T> the expected type * @author <a href="ales.justin@jboss.com">Ales Justin</a> */ public abstract class MultipleVFSParsingDeployer<T> extends AbstractVFSParsingDeployer<T> { private Map<String, Class<?>> mappings; private Class<?> suffixClass; public MultipleVFSParsingDeployer(Class<T> output, Map<String, Class<?>> mappings) { this(output, mappings, null, null); } public MultipleVFSParsingDeployer(Class<T> output, Map<String, Class<?>> mappings, String suffix, Class<?> suffixClass) { super(output); if (mappings == null || mappings.isEmpty()) throw new IllegalArgumentException("Illegal mappings"); if (suffix != null && suffixClass == null) throw new IllegalArgumentException("Null suffix class"); this.mappings = mappings; setNames(mappings.keySet()); setSuffix(suffix); this.suffixClass = suffixClass; } /** * Match file to mapping metadata class. * * @param unit the deployment unit * @param file the file * @return matching metadata class */ protected Class<?> matchFileToClass(DeploymentUnit unit, VirtualFile file) { if (file == null) throw new IllegalArgumentException("Null file"); return matchFileToClass(unit, file.getName(), true); } protected Class<?> matchFileToClass(DeploymentUnit unit, String fileName) { return matchFileToClass(unit, fileName, false); } /** * Match file name mappings. * * @param unit the deployment unit * @param fileName the file name * @param throwException should we throw an exception if no match found * @return match or null or IllegalArgumentException */ protected Class<?> matchFileToClass(DeploymentUnit unit, String fileName, boolean throwException) { if (fileName == null) throw new IllegalArgumentException("Null file name"); Map<String, Class<?>> altMappingsMap = getAltMappings(unit); if (altMappingsMap != null) { Class<?> result = altMappingsMap.get(fileName); if (result != null) return result; } Class<?> result = mappings.get(fileName); if (result == null) { if (getSuffix() != null && fileName.endsWith(getSuffix())) result = suffixClass; } if (result == null && throwException) throw new IllegalArgumentException( "Should not be here, file name '" + fileName + "' must macth some mapping " + mappings + " or suffix " + getSuffix() ); return result; } @SuppressWarnings("unchecked") protected T parse(VFSDeploymentUnit unit, VirtualFile file, T root) throws Exception { Class<?> expectedType = matchFileToClass(unit, file); if (getOutput().isAssignableFrom(expectedType) == false) throw new IllegalArgumentException("Matched " + expectedType + " which is not assignable to output " + getOutput()); if (root != null && expectedType.isInstance(root) == false) throw new IllegalArgumentException("Illegal root type: " + root + ", expecting " + expectedType); return (T)parse(expectedType, file, root); } /** * Parse file to produce expected class metadata. * * Root doesn't have U signature, since it conflicts * with its usage in the parse(VFSDeployment unit, VirtualFile file, T root) method. * * @param <U> the expect type * @param expectedType the expected class * @param file the file to parse * @param root the previous root * @return new metadata instance * @throws Exception for any error */ protected abstract <U> U parse(Class<U> expectedType, VirtualFile file, Object root) throws Exception; protected T mergeFiles(VFSDeploymentUnit unit, T root, List<VirtualFile> files, Set<String> missingFiles) throws Exception { Map<Class<?> , List<Object>> metadata = new HashMap<Class<?>, List<Object>>(); for (VirtualFile file : files) { Class<?> clazz = matchFileToClass(unit, file); List<Object> instances = metadata.get(clazz); if (instances == null) { instances = new ArrayList<Object>(); metadata.put(clazz, instances); } Object instance = parse(clazz, file, root); instances.add(instance); } return mergeMetaData(unit, root, metadata, missingFiles); } /** * Merge metadatas into single piece of metatdata * * @param unit the unit * @param root possibly null pre-existing root * @param metadata the metadatas * @param missingFiles file names that are missing matching file * @return merged metadata * @throws Exception for any error */ protected T mergeMetaData(VFSDeploymentUnit unit, T root, Map<Class<?>, List<Object>> metadata, Set<String> missingFiles) throws Exception { return mergeMetaData(unit, metadata); } /** * Merge metadatas into single piece of metatdata * * @param unit the unit * @param metadata the metadatas * @return merged metadata * @throws Exception for any error */ protected abstract T mergeMetaData(VFSDeploymentUnit unit, Map<Class<?>, List<Object>> metadata) throws Exception; /** * Get single metadata instance from metadata. * * @param <S> the metadata type * @param metadata the metadatas map * @param clazz metadata class * @return matching metadata instance */ protected <S> S getInstance(Map<Class<?>, List<Object>> metadata, Class<S> clazz) { List<Object> instances = metadata.get(clazz); if (instances == null || instances.isEmpty()) return null; else if (instances.size() > 1) throw new IllegalArgumentException("Expecting single instance: " + metadata); return clazz.cast(instances.iterator().next()); } /** * Get mappings. * * @return the mappings */ public Map<String, Class<?>> getMappings() { return mappings; } /** * Get suffix class. * * @return the suffix mathing class */ public Class<?> getSuffixClass() { return suffixClass; } }