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