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.servicemix.components.cache;
018    
019    import java.util.Map;
020    
021    import javax.jbi.JBIException;
022    import javax.jbi.messaging.Fault;
023    import javax.jbi.messaging.InOut;
024    import javax.jbi.messaging.MessageExchange;
025    import javax.jbi.messaging.MessagingException;
026    import javax.jbi.messaging.NormalizedMessage;
027    
028    import org.apache.servicemix.components.util.TransformComponentSupport;
029    import org.apache.servicemix.expression.Expression;
030    import org.apache.servicemix.expression.PropertyExpression;
031    import org.apache.servicemix.jbi.NoOutMessageAvailableException;
032    
033    /**
034     * Implements a caching layer on top of a service invocation to avoid calling an expensive remote service too often.
035     * The cache can be a simple Map based cache or a full <a href="http://www.jcp.org/en/jsr/detail?id=107">JCache</a> instance.
036     *
037     * @version $Revision: 2153 $
038     */
039    public class CacheComponent extends TransformComponentSupport {
040    
041        public static final PropertyExpression KEY_PROPERTY_EXPRESSION = new PropertyExpression("org.apache.servicemix.key");
042    
043        private Map cache;
044        private Expression keyExpression = KEY_PROPERTY_EXPRESSION;
045    
046        public Map getCache() {
047            return cache;
048        }
049    
050        public void setCache(Map cache) {
051            this.cache = cache;
052        }
053    
054        public Expression getKeyExpression() {
055            return keyExpression;
056        }
057    
058        public void setKeyExpression(Expression keyExpression) {
059            this.keyExpression = keyExpression;
060        }
061    
062    
063        // Implementation methods
064        //-------------------------------------------------------------------------
065        protected void init() throws JBIException {
066            super.init();
067            if (cache == null) {
068                throw new JBIException("You must specify a cache property");
069            }
070        }
071    
072        protected boolean transform(MessageExchange exchange, NormalizedMessage in, NormalizedMessage out) throws MessagingException {
073            Object key = keyExpression.evaluate(exchange, in);
074            if (key != null) {
075                NormalizedMessage message = (NormalizedMessage) cache.get(key);
076                if (message != null) {
077                    getMessageTransformer().transform(exchange, message, out);
078                    return true;
079                }
080            }
081    
082            InOut inOut = getExchangeFactory().createInOutExchange();
083            NormalizedMessage request = inOut.createMessage();
084            getMessageTransformer().transform(exchange, in, request);
085            inOut.setInMessage(request);
086            getDeliveryChannel().sendSync(inOut);
087    
088            NormalizedMessage response = inOut.getOutMessage();
089            Fault fault = inOut.getFault();
090            Exception error = inOut.getError();
091            if (fault != null) {
092                fail(exchange, fault);
093            }
094            else if (error != null) {
095                fail(exchange, error);
096            }
097            else if (response != null) {
098                getMessageTransformer().transform(exchange, response, out);
099    
100                if (key != null) {
101                    cache.put(key, response);
102                }
103            }
104            else {
105                throw new NoOutMessageAvailableException(exchange);
106            }
107            return true;
108        }
109    
110    }