001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.builder.xml;
018    
019    import java.io.File;
020    import java.io.InputStream;
021    import javax.xml.transform.Source;
022    import javax.xml.transform.TransformerException;
023    import javax.xml.transform.URIResolver;
024    import javax.xml.transform.stream.StreamSource;
025    
026    import org.apache.camel.spi.ClassResolver;
027    import org.apache.camel.util.FileUtil;
028    import org.apache.camel.util.ObjectHelper;
029    import org.slf4j.Logger;
030    import org.slf4j.LoggerFactory;
031    
032    /**
033     * Camel specific {@link javax.xml.transform.URIResolver} which is capable of loading files
034     * from the classpath and file system.
035     * <p/>
036     * Use prefix <tt>classpath:</tt> or <tt>file:</tt> to denote either classpath or file system.
037     * If no prefix is provided then the prefix from the <tt>location</tt> parameter is used.
038     * If it neither has a prefix then <tt>classpath:</tt> is used.
039     * <p/>
040     * This implementation <b>cannot</b> load files over http.
041     *
042     * @version 
043     */
044    public class XsltUriResolver implements URIResolver {
045    
046        private static final transient Logger LOG = LoggerFactory.getLogger(XsltUriResolver.class); 
047    
048        private final ClassResolver resolver;
049        private final String location;
050    
051        public XsltUriResolver(ClassResolver resolver, String location) {
052            this.resolver = resolver;
053            this.location = location;
054        }
055    
056        public Source resolve(String href, String base) throws TransformerException {
057            if (ObjectHelper.isEmpty(href)) {
058                throw new TransformerException("include href is empty");
059            }
060    
061            LOG.trace("Resolving URI with href: {} and base: {}", href, base);
062    
063            if (href.startsWith("classpath:")) {
064                LOG.debug("Resolving URI from classpath: {}", href);
065    
066                String name = ObjectHelper.after(href, ":");
067                InputStream is = resolver.loadResourceAsStream(name);
068                if (is == null) {
069                    throw new TransformerException("Cannot find " + name + " in classpath");
070                }
071                return new StreamSource(is);
072            }
073    
074            if (href.startsWith("file:")) {
075                LOG.debug("Resolving URI from file: {}", href);
076    
077                String name = ObjectHelper.after(href, ":");
078                File file = new File(name);
079                if (!file.exists()) {
080                    throw new TransformerException("Cannot find " + name + " in the file system");
081                }
082                return new StreamSource(file);
083            }
084    
085            // okay then its relative to the starting location from the XSLT component
086            String path = FileUtil.onlyPath(location);
087            if (ObjectHelper.isEmpty(path)) {
088                // default to use classpath: location
089                path = "classpath:" + href;
090                return resolve(path, base);
091            } else {
092                // default to use classpath: location
093                path = "classpath:" + path + "/" + href;
094                return resolve(path, base);
095            }
096        }
097        
098    }