/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.utils.cache.resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
import org.apereo.portal.xml.ResourceLoaderURIResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
/**
* Parses the provided input stream into a {@link Templates} object.
*
*/
@Service
public class TemplatesBuilder implements Loader<Templates>, ResourceLoaderAware {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
private ResourceLoader resourceLoader;
private Map<String, Object> transformerAttributes;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void setTransformerAttributes(Map<String, Object> transformerAttributes) {
this.transformerAttributes = transformerAttributes;
}
/* (non-Javadoc)
* @see org.apereo.portal.utils.cache.resource.ResourceBuilder#buildResource(org.springframework.core.io.Resource, java.io.InputStream)
*/
@Override
public LoadedResource<Templates> loadResource(Resource resource) throws IOException {
final TransformerFactory transformerFactory = TransformerFactory.newInstance();
if (this.transformerAttributes != null) {
for (final Map.Entry<String, Object> attributeEntry :
this.transformerAttributes.entrySet()) {
transformerFactory.setAttribute(attributeEntry.getKey(), attributeEntry.getValue());
}
}
final ResourceTrackingURIResolver uriResolver =
new ResourceTrackingURIResolver(this.resourceLoader);
transformerFactory.setURIResolver(uriResolver);
final URI uri = resource.getURI();
final String systemId = uri.toString();
final InputStream stream = resource.getInputStream();
final Templates templates;
try {
final StreamSource source = new StreamSource(stream, systemId);
templates = transformerFactory.newTemplates(source);
} catch (TransformerConfigurationException e) {
throw new IOException("Failed to parse stream into Templates", e);
} finally {
IOUtils.closeQuietly(stream);
}
final Map<Resource, Long> resolvedResources = uriResolver.getResolvedResources();
return new LoadedResourceImpl<Templates>(templates, resolvedResources);
}
private static class ResourceTrackingURIResolver extends ResourceLoaderURIResolver {
private final Map<Resource, Long> resolvedResources = new LinkedHashMap<Resource, Long>();
public ResourceTrackingURIResolver(ResourceLoader resourceLoader) {
super(resourceLoader);
}
@Override
protected Resource resolveResource(String href, String base) throws TransformerException {
final Resource resource = super.resolveResource(href, base);
long lastModified = 0;
try {
lastModified = resource.lastModified();
} catch (IOException e) {
//Ignore, not all resources can have a valid lastModified returned
}
resolvedResources.put(resource, lastModified);
return resource;
}
public Map<Resource, Long> getResolvedResources() {
return this.resolvedResources;
}
}
}