/* * Copyright (c) 2016 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.wicket.util.seed; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.Map; import javax.annotation.Nullable; import org.apache.wicket.protocol.http.WebApplication; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.transaction.annotation.Transactional; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.XStreamException; @SuppressWarnings("UnusedDeclaration") public class XstreamResourceDatabaseSeed implements DatabaseSeed, InitializingBean, ResourceLoaderAware { private static final Logger log = LoggerFactory.getLogger(XstreamResourceDatabaseSeed.class); private static final String RESOURCE_ENCODING = "ISO-8859-1"; private final XStream xstream = new XStream(); private Resource xstreamResource; private String[] xstreamResourcePatterns; private ResourcePatternResolver resolver; @Nullable private Map<String, Class<?>> aliases; private boolean developmentSeed = false; @Override @Transactional public void seedDatabase(WebApplication application) { if(!shouldSeed(application)) { return; } if(xstreamResource != null && xstreamResource.exists()) { Object result = handleXtreamResource(xstreamResource); handleXstreamResult(result); } if(xstreamResourcePatterns != null) { for(String locationPattern : xstreamResourcePatterns) { try { Resource[] resources = resolver.getResources(locationPattern); if(resources != null) { for(Resource resource : resources) { Object result = handleXtreamResource(resource); handleXstreamResult(resource, result); } } } catch(IOException e) { log.error("Error resolving resource pattern {}: {}", locationPattern, e.getMessage()); throw new RuntimeException(e); } } } } @Override public void afterPropertiesSet() throws Exception { if((xstreamResource == null || !xstreamResource.exists()) && (xstreamResourcePatterns == null || xstreamResourcePatterns.length == 0)) { log.error( "XStream resource not specified, no seeding will take place. Make sure the 'resource' or 'resourcePatterns' property are set."); } else { initializeXstream(xstream); } } public void setResourcePatterns(String... xstreamResourcePatterns) { this.xstreamResourcePatterns = xstreamResourcePatterns; } public void setResource(Resource xstreamResource) { this.xstreamResource = xstreamResource; } protected Resource getResource() { return xstreamResource; } public void setAliases(@Nullable Map<String, Class<?>> aliases) { this.aliases = aliases; } public void setDevelopmentSeed(boolean devSeed) { developmentSeed = devSeed; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { resolver = (ResourcePatternResolver) resourceLoader; } protected boolean shouldSeed(WebApplication application) { if(developmentSeed) { // If this is a development seed, only seed if the WebApplication // was deployed // in development mode if(!WebApplication.DEVELOPMENT.equalsIgnoreCase(application.getConfigurationType())) { return false; } } else { // If this is not a development seed, only seed if the // WebApplication was deployed // in deployment mode if(!WebApplication.DEPLOYMENT.equalsIgnoreCase(application.getConfigurationType())) { return false; } } return true; } /** * Called after 'resource' has been processed. * * @param result */ protected void handleXstreamResult(Object result) { } /** * Called after one resource from 'resourcePatterns' has been processed. * * @param resource * @param result */ protected void handleXstreamResult(Resource resource, Object result) { } /** * Given a {@code Resource} this method passes the underlying {@code InputStream} to the configured {@code XStream} * instance. * * @param resource the {@code Resource} to load * @return the result of {@code XStream#fromXML(java.io.Reader)} */ protected Object handleXtreamResource(Resource resource) { log.info("Loading resource {}.", resource); InputStreamReader reader = null; try { reader = new InputStreamReader(resource.getInputStream(), RESOURCE_ENCODING); return xstream.fromXML(new InputStreamReader(resource.getInputStream(), RESOURCE_ENCODING)); } catch(UnsupportedEncodingException e) { throw new RuntimeException(e); } catch(IOException e) { log.error("Error parsing XStream resource {}: {}", resource, e.getMessage()); throw new RuntimeException(e); } catch(XStreamException e) { log.error("Invalid XStream resource {}: {}", resource, e.getMessage()); throw e; } catch(RuntimeException e) { log.error("Error parsing XStream resource {}: {}", resource, e.getMessage()); throw e; } finally { if(reader != null) { try { reader.close(); } catch(Exception e) { // ignore } } } } protected void initializeXstream(XStream xstream) { xstream.setMode(XStream.ID_REFERENCES); if(aliases != null) { for(Map.Entry<String, Class<?>> aliasEntry : aliases.entrySet()) { log.debug("Adding XStream alias '{}' for class {}", aliasEntry.getKey(), aliasEntry.getValue()); xstream.alias(aliasEntry.getKey(), aliasEntry.getValue()); } } } }