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