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.component;
018
019import java.io.ByteArrayInputStream;
020import java.io.IOException;
021import java.io.InputStream;
022
023import org.apache.camel.Component;
024import org.apache.camel.api.management.ManagedAttribute;
025import org.apache.camel.api.management.ManagedOperation;
026import org.apache.camel.api.management.ManagedResource;
027import org.apache.camel.api.management.mbean.ManagedResourceEndpointMBean;
028import org.apache.camel.converter.IOConverter;
029import org.apache.camel.impl.ProcessorEndpoint;
030import org.apache.camel.spi.UriParam;
031import org.apache.camel.spi.UriPath;
032import org.apache.camel.util.IOHelper;
033import org.apache.camel.util.ResourceHelper;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037/**
038 * A useful base class for endpoints which depend on a resource
039 * such as things like Velocity or XQuery based components.
040 */
041@ManagedResource(description = "Managed ResourceEndpoint")
042public abstract class ResourceEndpoint extends ProcessorEndpoint implements ManagedResourceEndpointMBean {
043    protected final Logger log = LoggerFactory.getLogger(getClass());
044    private volatile byte[] buffer;
045    @UriPath(description = "Path to the resource")
046    private String resourceUri;
047    @UriParam(defaultValue = "false", description = "Sets whether to use resource content cache or not")
048    private boolean contentCache;
049
050    public ResourceEndpoint() {
051    }
052
053    public ResourceEndpoint(String endpointUri, Component component, String resourceUri) {
054        super(endpointUri, component);
055        this.resourceUri = resourceUri;
056    }
057
058    /**
059     * Gets the resource as an input stream considering the cache flag as well.
060     * <p/>
061     * If cache is enabled then the resource content is cached in an internal buffer and this content is
062     * returned to avoid loading the resource over and over again.
063     *
064     * @return the input stream
065     * @throws IOException is thrown if error loading the content of the resource to the local cache buffer
066     */
067    public InputStream getResourceAsInputStream() throws IOException {
068        // try to get the resource input stream
069        InputStream is;
070        if (isContentCache()) {
071            synchronized (this) {
072                if (buffer == null) {
073                    log.debug("Reading resource: {} into the content cache", resourceUri);
074                    is = getResourceAsInputStreamWithoutCache();
075                    buffer = IOConverter.toBytes(is);
076                    IOHelper.close(is, resourceUri, log);
077                }
078            }
079            log.debug("Using resource: {} from the content cache", resourceUri);
080            return new ByteArrayInputStream(buffer);
081        }
082
083        return getResourceAsInputStreamWithoutCache();
084    }
085
086    protected InputStream getResourceAsInputStreamWithoutCache() throws IOException {
087        return loadResource(resourceUri);
088    }
089
090    /**
091     * Loads the given resource.
092     *
093     * @param uri uri of the resource.
094     * @return the loaded resource
095     * @throws IOException is thrown if resource is not found or cannot be loaded
096     */
097    protected InputStream loadResource(String uri) throws IOException {
098        return ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext().getClassResolver(), uri);
099    }
100
101    @ManagedAttribute(description = "Whether the resource is cached")
102    public boolean isContentCache() {
103        return contentCache;
104    }
105
106    @ManagedOperation(description = "Clears the cached resource, forcing to re-load the resource on next request")
107    public void clearContentCache() {
108        log.debug("Clearing resource: {} from the content cache", resourceUri);
109        buffer = null;
110    }
111
112    public boolean isContentCacheCleared() {
113        return buffer == null;
114    }
115
116    @ManagedAttribute(description = "Camel context ID")
117    public String getCamelId() {
118        return getCamelContext().getName();
119    }
120
121    @ManagedAttribute(description = "Camel ManagementName")
122    public String getCamelManagementName() {
123        return getCamelContext().getManagementName();
124    }
125
126    @ManagedAttribute(description = "Endpoint service state")
127    public String getState() {
128        return getStatus().name();
129    }
130
131    /**
132     * Sets whether to use resource content cache or not.
133     */
134    public void setContentCache(boolean contentCache) {
135        this.contentCache = contentCache;
136    }
137
138    public String getResourceUri() {
139        return resourceUri;
140    }
141
142    /**
143     * Path to the resource
144     *
145     * @param resourceUri  the resource path
146     */
147    public void setResourceUri(String resourceUri) {
148        this.resourceUri = resourceUri;
149    }
150}