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.xmpp;
018    
019    import java.util.Iterator;
020    
021    import org.apache.camel.Consumer;
022    import org.apache.camel.ExchangePattern;
023    import org.apache.camel.Processor;
024    import org.apache.camel.Producer;
025    import org.apache.camel.impl.DefaultEndpoint;
026    import org.apache.camel.util.ObjectHelper;
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.jivesoftware.smack.AccountManager;
030    import org.jivesoftware.smack.ConnectionConfiguration;
031    import org.jivesoftware.smack.XMPPConnection;
032    import org.jivesoftware.smack.XMPPException;
033    import org.jivesoftware.smack.packet.Message;
034    import org.jivesoftware.smackx.muc.MultiUserChat;
035    
036    /**
037     * A XMPP Endpoint
038     *
039     * @version $Revision:520964 $
040     */
041    public class XmppEndpoint extends DefaultEndpoint<XmppExchange> {
042        private static final transient Log LOG = LogFactory.getLog(XmppEndpoint.class);
043        private XmppBinding binding;
044        private String host;
045        private int port;
046        private String user;
047        private String password;
048        private String resource = "Camel";
049        private boolean login = true;
050        private boolean createAccount;
051        private String room;
052        private String participant;
053        private String nickname;
054        private String serviceName;
055    
056        public XmppEndpoint(String uri, XmppComponent component) {
057            super(uri, component);
058            binding = new XmppBinding(component.getHeaderFilterStrategy());
059        }
060    
061        public XmppEndpoint(String endpointUri) {
062            super(endpointUri);
063        }
064    
065        public Producer<XmppExchange> createProducer() throws Exception {
066            if (room != null) {
067                return createGroupChatProducer();
068            } else {
069                if (getParticipant() == null) {
070                    throw new IllegalArgumentException("No room or participant configured on this endpoint: "
071                                                       + this);
072                }
073                return createPrivateChatProducer(getParticipant());
074            }
075        }
076    
077        public Producer<XmppExchange> createGroupChatProducer() throws Exception {
078            return new XmppGroupChatProducer(this);
079        }
080    
081        public Producer<XmppExchange> createPrivateChatProducer(String participant) throws Exception {
082            return new XmppPrivateChatProducer(this, participant);
083        }
084    
085        public Consumer<XmppExchange> createConsumer(Processor processor) throws Exception {
086            return new XmppConsumer(this, processor);
087        }
088    
089        @Override
090        public XmppExchange createExchange(ExchangePattern pattern) {
091            return new XmppExchange(getCamelContext(), pattern, getBinding());
092        }
093    
094        public XmppExchange createExchange(Message message) {
095            return new XmppExchange(getCamelContext(), getExchangePattern(), getBinding(), message);
096        }
097    
098        public boolean isSingleton() {
099            return true;
100        }
101    
102        public XMPPConnection createConnection() throws XMPPException {
103            XMPPConnection connection;
104    
105            if (port > 0) {
106                if (getServiceName() == null) {
107                    connection = new XMPPConnection(new ConnectionConfiguration(host, port));
108                } else {
109                    connection = new XMPPConnection(new ConnectionConfiguration(host, port, getServiceName()));
110                }
111            } else {
112                connection = new XMPPConnection(host);
113            }
114    
115            connection.connect();
116    
117            if (login && !connection.isAuthenticated()) {
118                if (user != null) {
119                    if (LOG.isDebugEnabled()) {
120                        LOG.debug("Logging in to XMPP as user: " + user + " on connection: " + getConnectionMessage(connection));
121                    }
122                    if (password == null) {
123                        LOG.warn("No password configured for user: " + user + " on connection: " + getConnectionMessage(connection));
124                    }
125    
126                    if (createAccount) {
127                        AccountManager accountManager = new AccountManager(connection);
128                        accountManager.createAccount(user, password);
129                    }
130                    if (resource != null) {
131                        connection.login(user, password, resource);
132                    } else {
133                        connection.login(user, password);
134                    }
135                } else {
136                    if (LOG.isDebugEnabled()) {
137                        LOG.debug("Logging in anonymously to XMPP on connection: "  + getConnectionMessage(connection));
138                    }
139                    connection.loginAnonymously();
140                }
141    
142                // presence is not needed to be sent after login
143            }
144    
145            return connection;
146        }
147    
148        /*
149         * If there is no "@" symbol in the room, find the chat service JID and
150         * return fully qualified JID for the room as room@conference.server.domain
151         */
152        public String resolveRoom(XMPPConnection connection) throws XMPPException {
153            ObjectHelper.notEmpty(room, "room");
154    
155            if (room.indexOf('@', 0) != -1) {
156                return room;
157            }
158    
159            Iterator<String> iterator = MultiUserChat.getServiceNames(connection).iterator();
160            if (!iterator.hasNext()) {
161                throw new XMPPException("Cannot find Multi User Chat service on connection: " + getConnectionMessage(connection));
162            }
163    
164            String chatServer = iterator.next();
165            if (LOG.isDebugEnabled()) {
166                LOG.debug("Detected chat server: " + chatServer);
167            }
168    
169            return room + "@" + chatServer;
170        }
171    
172        public static String getConnectionMessage(XMPPConnection connetion) {
173            return connetion.getHost() + ":" + connetion.getPort() + "/" + connetion.getServiceName();
174        }
175    
176        // Properties
177        // -------------------------------------------------------------------------
178        public XmppBinding getBinding() {
179            if (binding == null) {
180                binding = new XmppBinding();
181            }
182            return binding;
183        }
184    
185        /**
186         * Sets the binding used to convert from a Camel message to and from an XMPP
187         * message
188         */
189        public void setBinding(XmppBinding binding) {
190            this.binding = binding;
191        }
192    
193        public String getHost() {
194            return host;
195        }
196    
197        public void setHost(String host) {
198            this.host = host;
199        }
200    
201        public int getPort() {
202            return port;
203        }
204    
205        public void setPort(int port) {
206            this.port = port;
207        }
208    
209        public String getUser() {
210            return user;
211        }
212    
213        public void setUser(String user) {
214            this.user = user;
215        }
216    
217        public String getPassword() {
218            return password;
219        }
220    
221        public void setPassword(String password) {
222            this.password = password;
223        }
224    
225        public String getResource() {
226            return resource;
227        }
228    
229        public void setResource(String resource) {
230            this.resource = resource;
231        }
232    
233        public boolean isLogin() {
234            return login;
235        }
236    
237        public void setLogin(boolean login) {
238            this.login = login;
239        }
240    
241        public boolean isCreateAccount() {
242            return createAccount;
243        }
244    
245        public void setCreateAccount(boolean createAccount) {
246            this.createAccount = createAccount;
247        }
248    
249        public String getRoom() {
250            return room;
251        }
252    
253        public void setRoom(String room) {
254            this.room = room;
255        }
256    
257        public String getParticipant() {
258            // participant is optional so use user if not provided
259            return participant != null ? participant : user;
260        }
261    
262        public void setParticipant(String participant) {
263            this.participant = participant;
264        }
265    
266        public String getNickname() {
267            return nickname != null ? nickname : getUser();
268        }
269    
270        public void setNickname(String nickname) {
271            this.nickname = nickname;
272        }
273    
274        public void setServiceName(String serviceName) {
275            this.serviceName = serviceName;
276        }
277    
278        public String getServiceName() {
279            return serviceName;
280        }    
281        
282        // Implementation methods
283        // -------------------------------------------------------------------------
284    
285    }