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.activemq.broker;
018    
019    import java.net.InetAddress;
020    import java.net.URI;
021    import java.net.UnknownHostException;
022    import java.util.Locale;
023    
024    import org.apache.activemq.util.InetAddressUtil;
025    
026    /**
027     * Policy object that controls how a TransportConnector publishes the connector's
028     * address to the outside world.  By default the connector will publish itself
029     * using the resolved host name of the bound server socket.
030     *
031     * @org.apache.xbean.XBean
032     */
033    public class PublishedAddressPolicy {
034    
035        private String clusterClientUriQuery;
036        private PublishedHostStrategy publishedHostStrategy = PublishedHostStrategy.DEFAULT;
037    
038        /**
039         * Defines the value of the published host value.
040         */
041        public enum PublishedHostStrategy {
042            DEFAULT,
043            IPADDRESS,
044            HOSTNAME,
045            FQDN;
046    
047            public static PublishedHostStrategy getValue(String value) {
048                return valueOf(value.toUpperCase(Locale.ENGLISH));
049            }
050        }
051    
052        /**
053         * Using the supplied TransportConnector this method returns the String that will
054         * be used to update clients with this connector's connect address.
055         *
056         * @param connector
057         *      The TransportConnector whose address is to be published.
058         * @return a string URI address that a client can use to connect to this Transport.
059         * @throws Exception
060         */
061        public String getPublishableConnectString(TransportConnector connector) throws Exception {
062    
063            URI connectorURI = connector.getConnectUri();
064    
065            if (connectorURI == null) {
066                return null;
067            }
068    
069            String scheme = connectorURI.getScheme();
070            String userInfo = getPublishedUserInfoValue(connectorURI.getUserInfo());
071            String host = getPublishedHostValue(connectorURI.getHost());
072            int port = connectorURI.getPort();
073            String path = getPublishedPathValue(connectorURI.getPath());
074            String fragment = getPublishedFragmentValue(connectorURI.getFragment());
075    
076            URI publishedURI = new URI(scheme, userInfo, host, port, path, getClusterClientUriQuery(), fragment);
077    
078            return publishedURI.toString();
079        }
080    
081        /**
082         * Subclasses can override what host value is published by implementing alternate
083         * logic for this method.
084         *
085         * @param uriHostEntry
086         * @return
087         * @throws UnknownHostException
088         */
089        protected String getPublishedHostValue(String uriHostEntry) throws UnknownHostException {
090    
091            // By default we just republish what was already present.
092            String result = uriHostEntry;
093    
094            if (this.publishedHostStrategy.equals(PublishedHostStrategy.IPADDRESS)) {
095                InetAddress address = InetAddress.getByName(uriHostEntry);
096                result = address.getHostAddress();
097            } else if (this.publishedHostStrategy.equals(PublishedHostStrategy.HOSTNAME)) {
098                InetAddress address = InetAddress.getByName(uriHostEntry);
099                if (address.isAnyLocalAddress()) {
100                    // make it more human readable and useful, an alternative to 0.0.0.0
101                    result = InetAddressUtil.getLocalHostName();
102                } else {
103                    result = address.getHostName();
104                }
105            } else if (this.publishedHostStrategy.equals(PublishedHostStrategy.FQDN)) {
106                InetAddress address = InetAddress.getByName(uriHostEntry);
107                if (address.isAnyLocalAddress()) {
108                    // make it more human readable and useful, an alternative to 0.0.0.0
109                    result = InetAddressUtil.getLocalHostName();
110                } else {
111                    result = address.getCanonicalHostName();
112                }
113            }
114    
115            return result;
116        }
117    
118        /**
119         * Subclasses can override what path value is published by implementing alternate
120         * logic for this method.  By default this method simply returns what was already
121         * set as the Path value in the original URI.
122         *
123         * @param uriPathEntry
124         *      The original value of the URI path.
125         *
126         * @return the desired value for the published URI's path.
127         */
128        protected String getPublishedPathValue(String uriPathEntry) {
129            return uriPathEntry;
130        }
131    
132        /**
133         * Subclasses can override what host value is published by implementing alternate
134         * logic for this method.  By default this method simply returns what was already
135         * set as the Fragment value in the original URI.
136         *
137         * @param uriFragmentEntry
138         *      The original value of the URI Fragment.
139         *
140         * @return the desired value for the published URI's Fragment.
141         */
142        protected String getPublishedFragmentValue(String uriFragmentEntry) {
143            return uriFragmentEntry;
144        }
145    
146        /**
147         * Subclasses can override what user info value is published by implementing alternate
148         * logic for this method.  By default this method simply returns what was already
149         * set as the UserInfo value in the original URI.
150         *
151         * @param uriUserInfoEntry
152         *      The original value of the URI user info.
153         *
154         * @return the desired value for the published URI's user info.
155         */
156        protected String getPublishedUserInfoValue(String uriUserInfoEntry) {
157            return uriUserInfoEntry;
158        }
159    
160        /**
161         * Gets the URI query that's configured on the published URI that's sent to client's
162         * when the cluster info is updated.
163         *
164         * @return the clusterClientUriQuery
165         */
166        public String getClusterClientUriQuery() {
167            return clusterClientUriQuery;
168        }
169    
170        /**
171         * Sets the URI query that's configured on the published URI that's sent to client's
172         * when the cluster info is updated.
173         *
174         * @param clusterClientUriQuery the clusterClientUriQuery to set
175         */
176        public void setClusterClientUriQuery(String clusterClientUriQuery) {
177            this.clusterClientUriQuery = clusterClientUriQuery;
178        }
179    
180        /**
181         * @return the publishedHostStrategy
182         */
183        public PublishedHostStrategy getPublishedHostStrategy() {
184            return publishedHostStrategy;
185        }
186    
187        /**
188         * @param publishedHostStrategy the publishedHostStrategy to set
189         */
190        public void setPublishedHostStrategy(PublishedHostStrategy strategy) {
191            this.publishedHostStrategy = strategy;
192        }
193    
194        /**
195         * @param publishedHostStrategy the publishedHostStrategy to set
196         */
197        public void setPublishedHostStrategy(String strategy) {
198            this.publishedHostStrategy = PublishedHostStrategy.getValue(strategy);
199        }
200    }