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