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.component.javaspace;
018    
019    import java.io.ByteArrayInputStream;
020    import java.io.ByteArrayOutputStream;
021    import java.io.File;
022    import java.io.ObjectInputStream;
023    import java.io.ObjectOutputStream;
024    import java.rmi.RemoteException;
025    import java.util.concurrent.ScheduledThreadPoolExecutor;
026    import java.util.concurrent.TimeUnit;
027    
028    import net.jini.core.entry.Entry;
029    import net.jini.core.lease.Lease;
030    import net.jini.core.transaction.CannotAbortException;
031    import net.jini.core.transaction.CannotCommitException;
032    import net.jini.core.transaction.Transaction;
033    import net.jini.core.transaction.UnknownTransactionException;
034    import net.jini.space.JavaSpace;
035    
036    import org.apache.camel.ExchangePattern;
037    import org.apache.camel.Message;
038    import org.apache.camel.Processor;
039    import org.apache.camel.RuntimeCamelException;
040    import org.apache.camel.impl.DefaultConsumer;
041    import org.apache.camel.impl.DefaultExchange;
042    import org.apache.camel.util.ExchangeHelper;
043    import org.apache.commons.logging.Log;
044    import org.apache.commons.logging.LogFactory;
045    
046    /**
047     * @{link Consumer} implementation for Javaspaces
048     * 
049     * @version $Revision: 15488 $
050     */
051    public class JavaSpaceConsumer extends DefaultConsumer {
052    
053        public static final int READ = 1;
054        public static final int TAKE = 0;
055        
056        @SuppressWarnings("unused")
057        private static final transient Log LOG = LogFactory.getLog(JavaSpaceConsumer.class);
058        
059        private final int concurrentConsumers;
060        private final boolean transactional;
061        private final long transactionTimeout;
062        private final String verb;
063        private final String templateId;
064        private final ScheduledThreadPoolExecutor executor;
065        private JavaSpace javaSpace;
066        private TransactionHelper transactionHelper;
067        
068        public JavaSpaceConsumer(final JavaSpaceEndpoint endpoint, Processor processor) throws Exception {
069            super(endpoint, processor);
070            this.concurrentConsumers = endpoint.getConcurrentConsumers();
071            this.transactional = endpoint.isTransactional();
072            this.transactionTimeout = endpoint.getTransactionTimeout();
073            this.verb = endpoint.getVerb();
074            this.templateId = endpoint.getTemplateId();
075            this.executor = new ScheduledThreadPoolExecutor(this.concurrentConsumers);
076        }
077    
078        protected void doStart() throws Exception {
079            // TODO: There should be a switch to enable/disable using this security hack
080            Utility.setSecurityPolicy("policy.all", "policy_consumer.all");
081    
082            int verb = TAKE;
083            if (this.verb.equalsIgnoreCase("read")) {
084                verb = READ;
085            }
086            javaSpace = JiniSpaceAccessor.findSpace(((JavaSpaceEndpoint) this.getEndpoint()).getRemaining(),
087                    ((JavaSpaceEndpoint) this.getEndpoint()).getSpaceName());
088            if (transactional) {
089                transactionHelper = TransactionHelper.getInstance(((JavaSpaceEndpoint) this.getEndpoint()).getRemaining());
090            }
091            for (int i = 0; i < concurrentConsumers; ++i) {
092                Task worker = new Task((JavaSpaceEndpoint) this.getEndpoint(), this.getProcessor(), javaSpace,
093                        transactionHelper, transactionTimeout, verb, templateId);
094                executor.scheduleWithFixedDelay(worker, 0, 1, TimeUnit.NANOSECONDS);
095            }
096    
097            (new File("policy_consumer.all")).delete();
098        }
099    
100        @Override
101        protected void doStop() throws Exception {
102            executor.shutdown();
103        }
104    
105    }
106    
107    class Task implements Runnable {
108    
109        private final JavaSpaceEndpoint endpoint;
110        private final Processor processor;
111        private final JavaSpace javaSpace;
112        private final TransactionHelper transactionHelper;
113        private final long transactionTimeout;
114        private final int verb;
115        private final Entry template;
116    
117        public Task(JavaSpaceEndpoint endpoint, Processor processor, JavaSpace javaSpace,
118                TransactionHelper transactionHelper, long transactionTimeout, int verb, String templateId) throws Exception {
119            this.endpoint = endpoint;
120            this.processor = processor;
121            this.javaSpace = javaSpace;
122            this.transactionHelper = transactionHelper;
123            this.transactionTimeout = transactionTimeout;
124            this.verb = verb;
125            if (templateId != null) {
126                Entry tmpl = (Entry) this.endpoint.getCamelContext().getRegistry().lookup(templateId);
127                template = javaSpace.snapshot(tmpl);
128            } else {
129                this.template = javaSpace.snapshot(new InEntry());
130            }
131        }
132    
133        public void run() {
134            Transaction tnx = null;
135            try {
136                DefaultExchange exchange = (DefaultExchange) endpoint.createExchange(ExchangePattern.InOut);
137                Message message = exchange.getIn();
138                if (transactionHelper != null) {
139                    tnx = transactionHelper.getJiniTransaction(transactionTimeout).transaction;
140                }
141                Entry entry = null;
142                switch (verb) {
143                case JavaSpaceConsumer.TAKE:
144                    entry = javaSpace.take(template, tnx, 100);
145                    break;
146                case JavaSpaceConsumer.READ:
147                    entry = javaSpace.read(template, tnx, 100);
148                    break;
149                default:
150                    throw new RuntimeCamelException("Wrong verb");
151                }
152                if (entry != null) {
153                    if (entry instanceof InEntry) {
154                        if (((InEntry) entry).binary) {
155                            message.setBody(((InEntry) entry).buffer);
156                        } else {
157                            ByteArrayInputStream bis = new ByteArrayInputStream(((InEntry) entry).buffer);
158                            ObjectInputStream ois = new ObjectInputStream(bis);
159                            Object obj = ois.readObject();
160                            message.setBody(obj);
161                        }
162                        processor.process(exchange);
163                        Message out = exchange.getOut();
164                        if (out.getBody() != null && ExchangeHelper.isOutCapable(exchange)) {
165                            OutEntry replyCamelEntry = new OutEntry();
166                            replyCamelEntry.correlationId = ((InEntry) entry).correlationId;
167                            if (out.getBody() instanceof byte[]) {
168                                replyCamelEntry.binary = true;
169                                replyCamelEntry.buffer = (byte[]) out.getBody();
170                            } else {
171                                ByteArrayOutputStream bos = new ByteArrayOutputStream();
172                                ObjectOutputStream oos = new ObjectOutputStream(bos);
173                                oos.writeObject(out.getBody());
174                                replyCamelEntry.binary = false;
175                                replyCamelEntry.buffer = bos.toByteArray();
176                            }
177                            javaSpace.write(replyCamelEntry, tnx, Lease.FOREVER);
178                        }
179                    } else {
180                        message.setBody(entry, Entry.class);
181                        processor.process(exchange);
182                    }
183                }
184    
185            } catch (Exception e) {
186                if (tnx != null) {
187                    try {
188                        tnx.abort();
189                    } catch (UnknownTransactionException e1) {
190                        throw new RuntimeCamelException(e1);
191                    } catch (CannotAbortException e1) {
192                        throw new RuntimeCamelException(e1);
193                    } catch (RemoteException e1) {
194                        throw new RuntimeCamelException(e1);
195                    }
196                }
197                throw new RuntimeCamelException(e);
198            } finally {
199                if (tnx != null) {
200                    try {
201                        tnx.commit();
202                    } catch (UnknownTransactionException e1) {
203                        throw new RuntimeCamelException(e1);
204                    } catch (RemoteException e1) {
205                        throw new RuntimeCamelException(e1);
206                    } catch (CannotCommitException e1) {
207                        throw new RuntimeCamelException(e1);
208                    }
209                }
210            }
211        }
212    
213    }