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 */
017package org.apache.camel.support.jsse;
018
019import java.io.FileInputStream;
020import java.io.FileNotFoundException;
021import java.io.IOException;
022import java.io.InputStream;
023import java.net.URL;
024import java.util.ArrayList;
025import java.util.List;
026
027import org.apache.camel.CamelContext;
028import org.apache.camel.CamelContextAware;
029import org.apache.camel.RuntimeCamelException;
030import org.apache.camel.spi.ClassResolver;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034/**
035 * Base class that provides optional integration with core Camel capabilities.
036 */
037public class JsseParameters implements CamelContextAware {
038    
039    private static final Logger LOG = LoggerFactory.getLogger(JsseParameters.class);
040    
041    private CamelContext context;
042
043    /**
044     * @see #setCamelContext(CamelContext)
045     */
046    @Override
047    public CamelContext getCamelContext() {
048        return context;
049    }
050
051    /**
052     * Sets the optional {@link CamelContext} used for integration with core capabilities
053     * such as Camel Property Placeholders and {@link ClassResolver}.
054     *
055     * @param context the context to use
056     */
057    @Override
058    public void setCamelContext(CamelContext context) {
059        this.context = context;
060    }
061    
062    /**
063     * Parses the value using the Camel Property Placeholder capabilities if
064     * a context is provided.  Otherwise returns {@code value} as is.
065     *
066     * @param value the string to replace property tokens in
067     * @return the value
068     * 
069     * @throws RuntimeCamelException if property placeholders were used and there was an error resolving them
070     *
071     * @see #setCamelContext(CamelContext)
072     */
073    protected String parsePropertyValue(String value) throws RuntimeCamelException {
074        if (this.getCamelContext() != null) {
075            try {
076                return this.getCamelContext().resolvePropertyPlaceholders(value);
077            } catch (Exception e) {
078                throw new RuntimeCamelException("Error parsing property value: " + value, e);
079            }
080        } else {
081            return value;
082        }
083    }
084    
085    /**
086     * Parses the values using the Camel Property Placeholder capabilities if
087     * a context is provided.  Otherwise returns {@code values} as is.
088     *
089     * @param values the list of strings to replace property tokens in
090     * @return the list of strings
091     * 
092     * @throws RuntimeCamelException if property placeholders were used and there was an error resolving them
093     *
094     * @see #parsePropertyValue(String)
095     */
096    protected List<String> parsePropertyValues(List<String> values) throws RuntimeCamelException {
097        if (this.getCamelContext() == null) {
098            return values;
099        } else {
100            List<String> parsedValues = new ArrayList<>(values.size());
101            for (String value : values) {
102                parsedValues.add(this.parsePropertyValue(value));
103            }
104            return parsedValues;
105        }
106    }
107    
108    /**
109     * Attempts to loads a resource using a number of different approaches.
110     * The loading of the resource, is attempted by treating the resource as a file path,
111     * a class path resource, a URL, and using the Camel Context's {@link ClassResolver} 
112     * if a context is available in that order. An exception is thrown if the resource
113     * cannot be resolved to readable input stream using any of the above methods.
114     * 
115     * @param resource the resource location
116     * @return the input stream for the resource
117     *
118     * @throws IOException if the resource cannot be resolved using any of the above methods
119     * 
120     * @see #setCamelContext(CamelContext)
121     */
122    protected InputStream resolveResource(String resource) throws IOException {
123        InputStream is = null;
124
125        // attempt as plain file first
126        try {
127            LOG.trace("Trying to open resource [{}] as a file.", resource);
128            is = new FileInputStream(resource);
129            LOG.debug("Opened resource [{}] as a file.", resource);
130        } catch (FileNotFoundException e) {
131            LOG.trace("Could not open resource [" + resource + "] as a file.", e);
132        }
133
134        // then prefer to use ClassResolver from CamelContext if possible
135        if (is == null && this.context != null) {
136            LOG.trace("Trying to open resource using the CamelContext ClassResolver [{}].", context.getClassResolver());
137            try {
138                is = context.getClassResolver().loadResourceAsStream(resource);
139                if (is == null) {
140                    LOG.trace("Could not to open resource [{}] using the CamelContext ClassResolver [{}].",
141                            resource, context.getClassResolver());
142                } else {
143                    LOG.debug("Opened resource [{}] using the CamelContext ClassResolver [{}].",
144                            resource, this.getClass().getClassLoader());
145                }
146            } catch (Throwable e) {
147                LOG.trace("Could not open resource [" + resource + "]  using the CamelContext ClassResolver.", e);
148            }
149        }
150
151        if (is == null && Thread.currentThread().getContextClassLoader() != null) {
152            LOG.trace("Trying to open resource [{}] as a class path resource with the TCCL [{}].",
153                      resource, Thread.currentThread().getContextClassLoader());
154            is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
155            
156            if (is == null) {
157                LOG.trace("Could not open resource [{}] as a class path resource using the TCCL [{}].",
158                          resource, Thread.currentThread().getContextClassLoader());
159            } else {
160                LOG.debug("Opened resource [{}] as a class path resource with the TCCL [{}].",
161                          resource, Thread.currentThread().getContextClassLoader());
162            }
163        }
164
165        if (is == null) {
166            LOG.trace("Trying to open resource [{}] as a class path resource using the classloader [{}].",
167                      resource, this.getClass().getClassLoader());
168            is = this.getClass().getResourceAsStream(resource);
169            
170            if (is == null) {
171                LOG.trace("Could not open resource [{}] as a class path resource using the classloader [{}].",
172                          resource, this.getClass().getClassLoader());
173            } else {
174                LOG.debug("Opened resource [{}] as a class path resource with the classloader [{}].",
175                          resource, this.getClass().getClassLoader());
176            }
177        }
178
179        if (is == null) {
180            try {
181                LOG.trace("Trying to open resource [{}] as a URL.", resource);
182                is = new URL(resource).openStream();
183                LOG.debug("Opened resource [{}] as a URL.", resource);
184            } catch (IOException e) {
185                LOG.trace("Could not open resource [" + resource + "] as a URL.", e);
186            }
187        }
188
189        if (is == null) {
190            throw new IOException("Could not open " + resource + " as a file, class path resource, or URL.");
191        }
192
193        return is;
194    }
195
196}