/*
* 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;
}
}