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.irc;
018    
019    import java.util.List;
020    
021    import org.apache.camel.Exchange;
022    import org.apache.camel.ExchangePattern;
023    import org.apache.camel.Processor;
024    import org.apache.camel.impl.DefaultEndpoint;
025    import org.apache.camel.impl.DefaultExchange;
026    import org.apache.camel.util.ObjectHelper;
027    
028    import org.apache.commons.logging.Log;
029    import org.apache.commons.logging.LogFactory;
030    
031    import org.schwering.irc.lib.IRCConnection;
032    import org.schwering.irc.lib.IRCEventAdapter;
033    import org.schwering.irc.lib.IRCModeParser;
034    import org.schwering.irc.lib.IRCUser;
035    
036    /**
037     * Defines the <a href="http://camel.apache.org/irc.html">IRC Endpoint</a>
038     *
039     * @version $Revision: 1043319 $
040     */
041    public class IrcEndpoint extends DefaultEndpoint {
042        private static final transient Log LOG = LogFactory.getLog(IrcEndpoint.class);
043        
044        private IrcBinding binding;
045        private IrcConfiguration configuration;
046        private IrcComponent component;
047    
048        public IrcEndpoint(String endpointUri, IrcComponent component, IrcConfiguration configuration) {
049            super(endpointUri, component);
050            this.component = component;
051            this.configuration = configuration;
052        }
053    
054        public boolean isSingleton() {
055            return true;
056        }
057    
058        public Exchange createExchange(ExchangePattern pattern) {
059            DefaultExchange exchange = new DefaultExchange(this, pattern);
060            exchange.setProperty(Exchange.BINDING, getBinding());
061            return exchange;
062        }
063    
064        public Exchange createOnPrivmsgExchange(String target, IRCUser user, String msg) {
065            DefaultExchange exchange = getExchange();
066            exchange.setIn(new IrcMessage("PRIVMSG", target, user, msg));
067            return exchange;
068        }
069    
070        public Exchange createOnNickExchange(IRCUser user, String newNick) {
071            DefaultExchange exchange = getExchange();
072            exchange.setIn(new IrcMessage("NICK", user, newNick));
073            return exchange;
074        }
075    
076        public Exchange createOnQuitExchange(IRCUser user, String msg) {
077            DefaultExchange exchange = getExchange();
078            exchange.setIn(new IrcMessage("QUIT", user, msg));
079            return exchange;
080        }
081    
082        public Exchange createOnJoinExchange(String channel, IRCUser user) {
083            DefaultExchange exchange = getExchange();
084            exchange.setIn(new IrcMessage("JOIN", channel, user));
085            return exchange;
086        }
087    
088        public Exchange createOnKickExchange(String channel, IRCUser user, String whoWasKickedNick, String msg) {
089            DefaultExchange exchange = getExchange();
090            exchange.setIn(new IrcMessage("KICK", channel, user, whoWasKickedNick, msg));
091            return exchange;
092        }
093    
094        public Exchange createOnModeExchange(String channel, IRCUser user, IRCModeParser modeParser) {
095            DefaultExchange exchange = getExchange();
096            exchange.setIn(new IrcMessage("MODE", channel, user, modeParser.getLine()));
097            return exchange;
098        }
099    
100        public Exchange createOnPartExchange(String channel, IRCUser user, String msg) {
101            DefaultExchange exchange = getExchange();
102            exchange.setIn(new IrcMessage("PART", channel, user, msg));
103            return exchange;
104        }
105    
106        public Exchange createOnReplyExchange(int num, String value, String msg) {
107            DefaultExchange exchange = getExchange();
108            exchange.setIn(new IrcMessage("REPLY", num, value, msg));
109            return exchange;
110        }
111    
112        public Exchange createOnTopicExchange(String channel, IRCUser user, String topic) {
113            DefaultExchange exchange = getExchange();
114            exchange.setIn(new IrcMessage("TOPIC", channel, user, topic));
115            return exchange;
116        }
117    
118        public IrcProducer createProducer() throws Exception {
119            return new IrcProducer(this, component.getIRCConnection(configuration));
120        }
121    
122        public IrcConsumer createConsumer(Processor processor) throws Exception {
123            return new IrcConsumer(this, processor, component.getIRCConnection(configuration));
124        }
125    
126        public IrcComponent getComponent() {
127            return component;
128        }
129    
130        public void setComponent(IrcComponent component) {
131            this.component = component;
132        }
133    
134        public IrcBinding getBinding() {
135            if (binding == null) {
136                binding = new IrcBinding();
137            }
138            return binding;
139        }
140    
141        public void setBinding(IrcBinding binding) {
142            this.binding = binding;
143        }
144    
145        public IrcConfiguration getConfiguration() {
146            return configuration;
147        }
148    
149        public void setConfiguration(IrcConfiguration configuration) {
150            this.configuration = configuration;
151        }
152    
153    
154        public void handleIrcError(int num, String msg) {
155            if (IRCEventAdapter.ERR_NICKNAMEINUSE == num) {
156                handleNickInUse();
157            }
158        }
159    
160        private void handleNickInUse() {
161            IRCConnection connection = component.getIRCConnection(configuration);
162            String nick = connection.getNick() + "-";
163    
164            // hackish but working approach to prevent an endless loop. Abort after 4 nick attempts.
165            if (nick.endsWith("----")) {
166                LOG.error("Unable to set nick: " + nick + " disconnecting");
167            } else {
168                LOG.warn("Unable to set nick: " + nick + " Retrying with " + nick + "-");
169                connection.doNick(nick);
170                // if the nick failure was doing startup channels weren't joined. So join
171                // the channels now. It's a no-op if the channels are already joined.
172                joinChannels();
173            }
174        }
175    
176        private DefaultExchange getExchange() {
177            DefaultExchange exchange = new DefaultExchange(this, getExchangePattern());
178            exchange.setProperty(Exchange.BINDING, getBinding());
179            return exchange;
180        }
181    
182    
183        public void joinChannels() {
184            for (String channel : configuration.getChannels()) {
185                joinChannel(channel);
186            }
187        }
188    
189        public void joinChannel(String channel) {
190    
191            List<String> channels = configuration.getChannels();
192    
193            IRCConnection connection = component.getIRCConnection(configuration);
194    
195            // check for key for channel
196            String key = configuration.getKey(channel);
197    
198            if (ObjectHelper.isNotEmpty(key)) {
199                if (LOG.isDebugEnabled()) {
200                    LOG.debug("Joining: " + channel + " using " + connection.getClass().getName() + " with key " + key);
201                }
202                connection.doJoin(channel, key);
203            } else {
204                if (LOG.isDebugEnabled()) {
205                    LOG.debug("Joining: " + channel + " using " + connection.getClass().getName());
206                }
207                connection.doJoin(channel);
208            }
209        }
210    }
211