package org.apache.struts2.oval.interceptor;
import com.opensymphony.xwork2.FileManager;
import com.opensymphony.xwork2.FileManagerFactory;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import net.sf.oval.configuration.Configurer;
import net.sf.oval.configuration.annotation.AnnotationsConfigurer;
import net.sf.oval.configuration.annotation.JPAAnnotationsConfigurer;
import net.sf.oval.configuration.xml.XMLConfigurer;
import org.apache.struts2.StrutsConstants;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class DefaultOValValidationManager implements OValValidationManager {
private static final Logger LOG = LoggerFactory.getLogger(DefaultOValValidationManager.class);
protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
protected final Map<String, List<Configurer>> validatorCache = new HashMap<String, List<Configurer>>();
protected final Map<String, Configurer> validatorFileCache = new HashMap<String, Configurer>();
protected boolean validateJPAAnnotations;
private boolean reloadConfigs;
private FileManager fileManager;
@Inject(value = StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, required = false)
public void setReloadingConfigs(String reloadingConfigs) {
this.reloadConfigs = Boolean.parseBoolean(reloadingConfigs);
}
@Inject
public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
this.fileManager = fileManagerFactory.getFileManager();
}
public synchronized List<Configurer> getConfigurers(Class clazz, String context, boolean validateJPAAnnotations) {
this.validateJPAAnnotations =validateJPAAnnotations;
final String validatorKey = buildValidatorKey(clazz, context);
if (validatorCache.containsKey(validatorKey)) {
if (reloadConfigs) {
List<Configurer> configurers = buildXMLConfigurers(clazz, context, true, null);
//add an annotation configurer
addAditionalConfigurers(configurers);
validatorCache.put(validatorKey, configurers);
}
} else {
List<Configurer> configurers = buildXMLConfigurers(clazz, context, false, null);
//add an annotation configurer
addAditionalConfigurers(configurers);
validatorCache.put(validatorKey, configurers);
}
// get the set of validator configs
return validatorCache.get(validatorKey);
}
private void addAditionalConfigurers(List<Configurer> configurers) {
AnnotationsConfigurer annotationsConfigurer = new AnnotationsConfigurer();
configurers.add(annotationsConfigurer);
if (validateJPAAnnotations) {
if (LOG.isDebugEnabled()) {
LOG.debug("Adding support for JPA annotations validations in OVal");
}
configurers.add(new JPAAnnotationsConfigurer());
}
}
protected static String buildValidatorKey(Class clazz, String context) {
StringBuilder sb = new StringBuilder(clazz.getName());
sb.append("/");
sb.append(context);
return sb.toString();
}
private List<Configurer> buildXMLConfigurers(Class clazz, String context, boolean checkFile, Set<String> checked) {
List<Configurer> configurers = new ArrayList<Configurer>();
if (checked == null) {
checked = new TreeSet<String>();
} else if (checked.contains(clazz.getName())) {
return configurers;
}
if (clazz.isInterface()) {
for (Class anInterface : clazz.getInterfaces()) {
configurers.addAll(buildXMLConfigurers(anInterface, context, checkFile, checked));
}
} else {
if (!clazz.equals(Object.class)) {
configurers.addAll(buildXMLConfigurers(clazz.getSuperclass(), context, checkFile, checked));
}
}
// look for validators for implemented interfaces
for (Class anInterface1 : clazz.getInterfaces()) {
if (checked.contains(anInterface1.getName())) {
continue;
}
addIfNotNull(configurers, buildClassValidatorConfigs(anInterface1, checkFile));
if (context != null) {
addIfNotNull(configurers, buildAliasValidatorConfigs(anInterface1, context, checkFile));
}
checked.add(anInterface1.getName());
}
addIfNotNull(configurers, buildClassValidatorConfigs(clazz, checkFile));
if (context != null) {
addIfNotNull(configurers, buildAliasValidatorConfigs(clazz, context, checkFile));
}
checked.add(clazz.getName());
return configurers;
}
protected void addIfNotNull(List<Configurer> configurers, Configurer configurer) {
if (configurer != null)
configurers.add(configurer);
}
protected XMLConfigurer buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX;
return loadFile(fileName, aClass, checkFile);
}
protected XMLConfigurer buildClassValidatorConfigs(Class aClass, boolean checkFile) {
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
return loadFile(fileName, aClass, checkFile);
}
protected XMLConfigurer loadFile(String fileName, Class clazz, boolean checkFile) {
URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz);
if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) {
java.io.InputStream is = null;
try {
is = fileManager.loadFile(fileUrl);
if (is != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading validation xml file [#0]", fileName);
}
XMLConfigurer configurer = new XMLConfigurer();
configurer.fromXML(is);
validatorFileCache.put(fileName, configurer);
return configurer;
}
} finally {
if (is != null) {
try {
is.close();
} catch (java.io.IOException e) {
LOG.error("Unable to close input stream for [#0] ", e, fileName);
}
}
}
} else {
return (XMLConfigurer) validatorFileCache.get(fileName);
}
return null;
}
}