/* * #%L * Service Locator Client for CXF * %% * Copyright (C) 2011 - 2012 Talend Inc. * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.talend.esb.servicelocator.client.internal; import java.util.logging.Level; import java.util.logging.Logger; /** * Representation of a ZooKeeper node path. The path is always absolute. As node names in ZooKeeper must not * contain the path separator ("/") NodePath takes care to {@link NodePath#encode(String) encode} the names, * so they can be stored in ZooKeeper. */ public class NodePath { public static final char SEPARATOR = '/'; private static final Logger LOG = Logger.getLogger(NodePath.class.getPackage().getName()); private String path; /** * Create an <code>NodePath</code> that consists of the given path segments. * * @param pathSegments * the sequence of path segments the NodePath consists of, must not be null or empty */ public NodePath(String... pathSegments) { if (pathSegments == null || pathSegments.length == 0) { LOG.log(Level.SEVERE, "At least one path segment must be defined."); throw new IllegalArgumentException("At least one path segment must be defined."); } StringBuffer rawPath = new StringBuffer(); for (String pathSegment : pathSegments) { checkValidPathSegment(pathSegment); String encodedPathSegment = encode(pathSegment); rawPath.append(SEPARATOR).append(encodedPathSegment); } path = rawPath.toString(); } protected NodePath(NodePath parentPath, String childPathSegment) { checkValidPathSegment(childPathSegment); path = parentPath.path + SEPARATOR + encode(childPathSegment); } protected NodePath(NodePath parentPath, String childPathSegment, boolean encoded) { checkValidPathSegment(childPathSegment); String encodedChildPathSegment = encoded ? childPathSegment : encode(childPathSegment); path = parentPath.path + SEPARATOR + encodedChildPathSegment; } /** * Create a <code>NodePath</code>, which is a child of this one. * * @param childNodeName * name of the child node, must not be <code>null</code> */ public NodePath child(String childNodeName) { return new NodePath(this, childNodeName); } /** * Create a <code>NodePath</code>, which is a child of this one. * * @param childNodeName * name of the child node, must not be <code>null</code> */ protected NodePath child(String childNodeName, boolean encoded) { return new NodePath(this, childNodeName, encoded); } @Override public boolean equals(Object obj) { if (!(obj instanceof NodePath)) { return false; } return path.equals(((NodePath) obj).path); } public String getNodeName() { int index = path.lastIndexOf(SEPARATOR); return decode(path.substring(index + 1)); } @Override public int hashCode() { return path.hashCode(); } /** * Encoded <code>String</code> representation of this <code>NodePath</code>. * * @return the <code>String</code> representation */ @Override public String toString() { return path; } private void checkValidPathSegment(String pathSegment) { if (pathSegment == null || pathSegment.isEmpty()) { throw new IllegalArgumentException("Path segments must not be null and not empty."); } } /** * Encode the given <code>String</code>. All occurrences of "/" are mapped to "%2A" and all occurrences of * "%" to "%2F". * * @param raw * the <code>String</code> to encode, must not be <code>null</code> * @return the encoded version * * @see #decode(String) */ public static String encode(String raw) { String encoded = raw.replace("%", "%2A"); encoded = encoded.replace("/", "%2F"); return encoded; } /** * Decode the given <code>String</code>. It is the inverse operation of {@link #encode(String)}. For all * <code>String</code>s <code>s</code>, <code>decode(encode(s)).equals(s)</code> should be * <code>true</code>. * * @param encoded * the <code>String</code> to decode, must not be <code>null</code> * @return the raw version * * @see #encode(String) */ public static String decode(String encoded) { String raw = encoded.replace("%2F", "/"); raw = raw.replace("%2A", "%"); return raw; } }