/**************************************************************************** * Copyright (c) 2005, 2010 Jan S. Rellermeyer, Systems Group, * Department of Computer Science, ETH Zurich and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Jan S. Rellermeyer - initial API and implementation * Markus Alexander Kuppe - enhancements and bug fixes * *****************************************************************************/ package ch.ethz.iks.slp; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; /** * Implementation of the SLP ServiceURL class defined in RFC 2614. * * @author Jan S. Rellermeyer, Systems Group, ETH Z�rich * @since 0.1 */ public final class ServiceURL extends ch.ethz.iks.slp.impl.AuthenticatedURL implements Serializable { /** * */ private static final long serialVersionUID = 9181946114021582389L; /** * */ public static final int NO_PORT = 0; /** * */ public static final int LIFETIME_NONE = 0; /** * */ public static final int LIFETIME_DEFAULT = 10800; /** * */ public static final int LIFETIME_MAXIMUM = 65535; /** * */ public static final int LIFETIME_PERMANENT = -1; /** * */ private String url = null;; /** * */ private int lifetime = 0; /** * */ private ServiceType type = null; /** * */ private String host = null; /** * user specific uri part */ private String userInfo = null; /** * */ private String protocol = null; /** * */ private int port = 0; /** * */ private String path = null; /** * * */ private ServiceURL() { } /** * create a new ServiceURL instance from a String. * * @param serviceURL * the string representation of a ServiceURL like * * <pre> * service::"serviceType"://"addrspec" * </pre> * * where servicetype should be of the form abstractType:concreteType and * addrspec is the hostname or dotted decimal notation of the host's address * followed by an optional :portNumber. Example: * * <pre> * service:osgi:remote://my.host.ch:9200 * </pre> * * @param lifeTime * the lifetime of the ServiceURL in seconds. * @throws ServiceLocationException * if the String is not parsable. */ public ServiceURL(final String serviceURL, final int lifeTime) throws ServiceLocationException { url = serviceURL; lifetime = lifeTime; try { parse(); } catch (Exception ex) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "service url is malformed: [" + url + "]. "); } } /** * parse the url string. * */ private void parse() { int pos1 = url.indexOf("://"); type = new ServiceType(url.substring(0, pos1++)); int pos2 = url.indexOf("://", pos1 + 1); if (pos2 > -1) { protocol = url.substring(pos1 + 2, pos2); pos1 = pos2 + 1; } int pathStart = url.indexOf("/", pos1 + 2); int hostEnd = url.indexOf(":", pos1 + 2); if (hostEnd == -1 || (pathStart != -1 && pathStart <= hostEnd)) { port = NO_PORT; hostEnd = pathStart; } else { pathStart = url.indexOf("/", hostEnd + 1); if (pathStart == -1) { port = Integer.parseInt(url.substring(hostEnd + 1)); } else { port = Integer.parseInt(url.substring(hostEnd + 1, pathStart)); } } int pos3 = url.indexOf("@"); if (pos3 > -1) { userInfo = url.substring(pos1 + 2, pos3); pos1 = pos3 - 1; } else { userInfo = ""; // no option user info } if (hostEnd == -1) { host = url.substring(pos1 + 2); } else { host = url.substring(pos1 + 2, hostEnd); } if (pathStart == -1) { path = ""; } else { path = url.substring(pathStart); } } /** * Check if two instances are equal. * * @inheritDoc java.lang.Object.equals(Object) * @param obj * the object to compare to. * @return true if the instances are equal. */ public boolean equals(final Object obj) { if (obj instanceof ServiceURL) { ServiceURL u = (ServiceURL) obj; return (type.equals(u.type) && host.equals(u.host) && port == u.port && ((protocol == null && u.protocol == null) || protocol .equals(u.protocol)) && path.equals(u.path)); } return false; } /** * Check if a ServiceURL matches another ServiceURL or a ServiceType. In the * first case, the method performs an equality check with equals(Object * obj), for ServiceTypes, the ServiceType part of the ServiceURL is checked * against the given ServiceType. * * @param obj * a ServiceURL or ServiceType. All other objects will return * false. * @return true if the match succeeds. */ public boolean matches(final Object obj) { if (obj instanceof ServiceURL) { return equals(obj); } else if (obj instanceof ServiceType) { return type.matches(obj); } return false; } /** * get a String representation of the ServiceURL. * * @return the String representation. */ public String toString() { return type.toString() + "://" + (protocol != null ? protocol + "://" : "") + ("".equals(userInfo) ? "": (userInfo + "@")) + host + (port != NO_PORT ? (":" + port) : "") + path; } /** * get the hashCode of the ServiceURL instance. * * @return the hashCode. */ public int hashCode() { return url.hashCode(); } /** * get the service type. * * @return the service type. */ public ServiceType getServiceType() { return type; } /** * get the transport method. * * @return the transport method. IP returns empty string. * @deprecated */ public String getTransport() { return ""; } /** * get the protocol. * * @return the protocol, if specified. Otherwise, returns null. */ public String getProtocol() { return protocol; } /** * get the host. * * @return the host. */ public String getHost() { return host; } /** * get the user info * * @return the user info or the empty string * @since 1.1 */ public String getUserInfo() { return userInfo; } /** * get the port. * * @return the port. */ public int getPort() { return port; } /** * get the URL path. * * @return the URL path. */ public String getURLPath() { return path; } /** * get the lifetime. * * @return the lifetime. */ public int getLifetime() { return lifetime; } /** * get the byte representation of the ServiceURL instance. * * @throws IOException * @throws IOException * if an internal processing error occurs. */ public void writeTo(DataOutputStream out) throws IOException { out.write(0); out.writeShort((short) lifetime); out.writeUTF(toString()); writeAuthBlock(out); } public int getLength() { return 1 + 2 + 2 + toString().length() + getAuthBlockLength(); } /** * Reads a byte stream from a DataInput and constructs a ServiceURL from it, * following the RFC 2608 schema: * <p> * * <pre> * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Reserved | Lifetime | URL Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |URL len, contd.| URL (variable length) \ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |# of URL auths | Auth. blocks (if any) \ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * </pre>. * </p> * * @param input * the DataInput streaming the ServiceURL bytes. * @return a ServiceURL instance. * @throws ServiceLocationException * in case of IO exceptions. * @throws IOException */ public static ServiceURL fromBytes(final DataInputStream input) throws ServiceLocationException, IOException { ServiceURL surl = new ServiceURL(); input.readByte(); surl.lifetime = input.readShort(); surl.url = input.readUTF(); surl.authBlocks = parseAuthBlock(input); try { surl.parse(); } catch (Exception ex) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "service url is malformed: [" + surl + "]. "); } return surl; } }