/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @version $Rev: 491396 $ $Date: 2006-12-31 01:06:13 -0500 (Sun, 31 Dec 2006) $
*/
package org.apache.yoko.orb.CosNaming;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.yoko.orb.OB.MinorCodes;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.ORB;
import org.omg.CORBA.SystemException;
import org.omg.CosNaming.BindingType;
import org.omg.CosNaming.BindingTypeHolder;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextHelper;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextExtPOA;
import org.omg.CosNaming.NamingContextExtPackage.InvalidAddress;
import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
import org.omg.CosNaming.NamingContextPackage.InvalidName;
import org.omg.CosNaming.NamingContextPackage.NotFoundReason;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.PortableServer.POA;
public abstract class NamingContextBase extends NamingContextExtPOA
{
// the real logger backing instance. We use the interface class as the locator
protected static final Logger logger = Logger.getLogger(NamingContext.class.getName());
// set of URL characters that don't require escaping when encoded.
protected final String nonEscaped = ";/?:@&=+$;-_.!~* ()";
// the orb we're attached to
protected ORB orb;
// the poa we're associated with
protected POA poa;
/**
* Create a new base NamingContext (super class constructor
* for the derived classes).
*
* @param orb The ORB this is hosted on.
*
* @exception java.lang.Exception
*/
public NamingContextBase(ORB orb, POA poa) throws java.lang.Exception {
super();
this.orb = orb;
this.poa = poa;
}
/**
* Bind an object to a given name.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
* @param obj The object to be bound.
*
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public void bind (org.omg.CosNaming.NameComponent[] n, org.omg.CORBA.Object obj) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName, org.omg.CosNaming.NamingContextPackage.AlreadyBound {
// perform various name validations
validateName(n);
logNameComponent("bind() name", n);
// do we need to push through to a deeper naming context first?
if (n.length > 1) {
// resolve the top level name to a context, and have that context
// resolve the rest.
NamingContext context = resolveContext(n[0]);
NameComponent[] subName = extractSubName(n);
// now pass this along to the next context for the real bind operation.
context.bind(subName, obj);
}
else {
NameComponent name = n[0];
// we need the resolveObject() and bindObject() calls to be consistent, so
// synchronize on this
synchronized (this) {
// see if we have this bound already...can't replace these.
BindingTypeHolder type = new BindingTypeHolder();
if (resolveObject(name, type) != null) {
throw new AlreadyBound();
}
type.value = BindingType.nobject;
// ok, this is a new binding, go do it.
bindObject(name, obj, type);
}
}
}
/**
* Rebind an object to a given name. If an object is
* already bound with this name, the new object replaces
* the bound object's value. If no object has been
* bound already, this is the same as a bind operation.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
* @param obj The new value for this binding.
*
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public void rebind (org.omg.CosNaming.NameComponent[] n, org.omg.CORBA.Object obj) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName {
// perform various name validations
validateName(n);
logNameComponent("rebind() name", n);
// do we need to push through to a deeper naming context first?
if (n.length > 1) {
// resolve the top level name to a context, and have that context
// resolve the rest.
NamingContext context = resolveContext(n[0]);
NameComponent[] subName = extractSubName(n);
// now pass this along to the next context for the real bind operation.
context.rebind(subName, obj);
}
else {
NameComponent name = n[0];
// we need the resolveObject() and bindObject() calls to be consistent, so
// synchronize on this
synchronized (this) {
// see if we have this bound already...can't replace these.
BindingTypeHolder type = new BindingTypeHolder();
// for a rebind, we must have an object, and it must be a real object
if (resolveObject(name, type) != null) {
// it has to resolve to a real object. If it is a naming context,
// then this is the wrong binding operation.
if (type.value.value() == BindingType._ncontext) {
throw new NotFound(NotFoundReason.not_object, n);
}
// safe to unbind
unbindObject(name);
}
type.value = BindingType.nobject;
// now bind this object
bindObject(name, obj, type);
}
}
}
/**
* Bind a new context to a given name.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
* @param nc The new naming context added to the tree.
*
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public void bind_context(org.omg.CosNaming.NameComponent[] n, org.omg.CosNaming.NamingContext nc) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName, org.omg.CosNaming.NamingContextPackage.AlreadyBound {
// perform various name validations
validateName(n);
logNameComponent("bind_context() name", n);
// do we need to push through to a deeper naming context first?
if (n.length > 1) {
// resolve the top level name to a context, and have that context
// resolve the rest.
NamingContext context = resolveContext(n[0]);
NameComponent[] subName = extractSubName(n);
// now pass this along to the next context for the real bind operation.
context.bind_context(subName, nc);
}
else {
NameComponent name = n[0];
// we need the resolveObject() and bindObject() calls to be consistent, so
// synchronize on this
synchronized (this) {
// see if we have this bound already...can't replace these.
BindingTypeHolder type = new BindingTypeHolder();
if (resolveObject(name, type) != null) {
throw new AlreadyBound();
}
type.value = BindingType.ncontext;
// ok, this is a new binding, go do it.
bindObject(name, nc, type);
}
}
}
/**
* Rebind a context to a given name. If a context is
* already bound with this name, the new context replaces
* the existing context. If no context has been
* bound already, this is the same as a bind operation.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
* @param nc The new context to be bound with the name.
*
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public void rebind_context (org.omg.CosNaming.NameComponent[] n, org.omg.CosNaming.NamingContext nc) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName {
// perform various name validations
validateName(n);
logNameComponent("rebind_context() name", n);
// do we need to push through to a deeper naming context first?
if (n.length > 1) {
// resolve the top level name to a context, and have that context
// resolve the rest.
NamingContext context = resolveContext(n[0]);
NameComponent[] subName = extractSubName(n);
// now pass this along to the next context for the real bind operation.
context.rebind_context(subName, nc);
}
else {
NameComponent name = n[0];
// we need the resolveObject() and bindObject() calls to be consistent, so
// synchronize on this
synchronized (this) {
// see if we have this bound already...can't replace these.
BindingTypeHolder type = new BindingTypeHolder();
// for a rebind, we must have an object, and it must be a real object
if (resolveObject(name, type) != null) {
// it has to resolve to a real object. If it is a naming context,
// then this is the wrong binding operation.
if (type.value.value() != BindingType._ncontext) {
throw new NotFound(NotFoundReason.not_context, n);
}
// safe to unbind
unbindObject(name);
}
type.value = BindingType.ncontext;
// now bind this object
bindObject(name, nc, type);
}
}
}
/**
* Resolve an an entry in the context tree. The
* resolved object may be a bound object or another
* NamingContext. If the named entry is not found,
* a NotFound exception is thrown.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
*
* @return The object bound at the indicated location.
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public org.omg.CORBA.Object resolve (org.omg.CosNaming.NameComponent[] n) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName {
// perform various name validations
validateName(n);
logNameComponent("resolve() name", n);
// do we need to push through to a deeper naming context first?
if (n.length > 1) {
// resolve the top level name to a context, and have that context
// resolve the rest.
NamingContext context = resolveContext(n[0]);
NameComponent[] subName = extractSubName(n);
// now pass this along to the next context for the real bind operation.
return context.resolve(subName);
}
else {
NameComponent name = n[0];
// see if we have this bound already...can't replace these.
BindingTypeHolder type = new BindingTypeHolder();
org.omg.CORBA.Object obj = resolveObject(name, type);
if (obj == null) {
// Object was not found
throw new NotFound(NotFoundReason.missing_node, n);
}
return obj;
}
}
/**
* Remove an entry from the context tree. The
* target object may be a bound object or another
* NamingContext. If the named entry is not found,
* a NotFound exception is thrown.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
*
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public void unbind (org.omg.CosNaming.NameComponent[] n) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName {
// perform various name validations
validateName(n);
logNameComponent("unbind() name", n);
// do we need to push through to a deeper naming context first?
if (n.length > 1) {
// resolve the top level name to a context, and have that context
// resolve the rest.
NamingContext context = resolveContext(n[0]);
NameComponent[] subName = extractSubName(n);
// now pass this along to the next context for the real bind operation.
context.unbind(subName);
}
else {
NameComponent name = n[0];
synchronized (this) {
// see if we have this bound already...can't replace these.
BindingTypeHolder type = new BindingTypeHolder();
org.omg.CORBA.Object obj = unbindObject(name);
if (obj == null) {
// Object was not found
throw new NotFound(NotFoundReason.missing_node, n);
}
}
}
}
/**
* Create a new context and bind it in at the target
* location.
*
* @param n An array of NameComponents that are the target name.
* The last element in the array is binding name for the
* object. The remainder of the array is the path
* for resolving the naming context, relative to the
* current context. All path contexts must already be
* bound in the context tree.
*
* @return The newly created context.
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
* @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound
*/
public synchronized org.omg.CosNaming.NamingContext bind_new_context(org.omg.CosNaming.NameComponent[] n) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.AlreadyBound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName {
logNameComponent("bind_new_context() name", n);
NamingContext context = new_context();
try {
bind_context(n, context);
NamingContext returnContext = context;
// transfer this to another variable so the finally block doesn't try to destroy this.
context = null;
return returnContext;
} finally {
// if there is a bind failure on this, we need to ensure the context has
// an opportunity to clean up any of its resources.
if (context != null) {
try {
context.destroy();
} catch (org.omg.CosNaming.NamingContextPackage.NotEmpty e) {
// new contexts should be empty.
}
}
}
}
/**
* Convert an array of NameComponents into the string
* form of a context name.
*
* @param n The array of NameComponents to convert.
*
* @return The context name, in string form.
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
*/
public String to_string(org.omg.CosNaming.NameComponent[] n) throws org.omg.CosNaming.NamingContextPackage.InvalidName {
validateName(n);
logNameComponent("to_string() name", n);
// convert the first part of the name
StringBuffer value = new StringBuffer();;
// convert the first component, then build up from there.
nameToString(n[0], value);
// the remainder need to get a separator
for (int i = 1; i < n.length; i++) {
value.append('/');
nameToString(n[i], value);
}
return value.toString();
}
/**
* Perform the reverse operation of the to_string() method,
* parsing a String context name into an array of
* NameComponents.
*
* @param sn The string form of the name.
*
* @return An array of NameComponents parsed from the String name.
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
*/
public org.omg.CosNaming.NameComponent[] to_name(String sn) throws org.omg.CosNaming.NamingContextPackage.InvalidName {
// must have a argument to parse
if (sn == null || sn.length() == 0) {
throw new InvalidName();
}
List components = new ArrayList();
StringBuffer component = new StringBuffer();
int index = 0;
String id = null;
String kind = null;
while (index < sn.length()) {
char ch = sn.charAt(index++);
// found an escape character or a delimiter?
if (ch == '\\') {
// nothing after the escape? Trouble
if (index >= sn.length()) {
throw new InvalidName();
}
// get the next character
ch = sn.charAt(index++);
component.append(ch);
}
// we need to process the periods here, to avoid getting
// mixed up with unescaped periods.
else if (ch == '.') {
// already seen a period while scanning? That's not allowed
if (id != null) {
throw new InvalidName();
}
// pull off the id piece and reset the buffer
id = component.toString();
component.setLength(0);
}
// found a component delimiter?
else if (ch == '/') {
// not seen a id/kind separator yet? This is an id with no kind
if (id == null) {
id = component.toString();
kind = "";
}
else {
// we have an id already, pull off the kind
kind = component.toString();
}
// add the parsed name component
components.add(new NameComponent(id, kind));
// make sure these are all reset after pulling off a component
component.setLength(0);
id = null;
kind = null;
}
else {
component.append(ch);
}
}
// parse the last section
// not seen a id/kind separator yet? This is an id with no kind
if (id == null) {
id = component.toString();
kind = "";
}
else {
// we have an id already, pull off the kind
kind = component.toString();
}
// add the parsed name component
components.add(new NameComponent(id, kind));
// and turn this into a component array
return (NameComponent[])components.toArray(new NameComponent[components.size()]);
}
/**
* Create a URL name for accessing a component by name. The
* URL will have a corbaname: protocol.
*
* @param addr The address location for the naming service used
* to resolve the object. This is in "host:port" form,
* just line a corbaloc: URL.
* @param sn The string mae of the target object.
*
* @return A URL for accessing this object, in String form.
* @exception org.omg.CosNaming.NamingContextExtPackage.InvalidAddress
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
*/
public String to_url (String addr, String sn) throws org.omg.CosNaming.NamingContextExtPackage.InvalidAddress, org.omg.CosNaming.NamingContextPackage.InvalidName {
// basic validation
if (addr == null || addr.length() == 0) {
throw new InvalidAddress();
}
if (sn == null || sn.length() == 0) {
throw new InvalidName();
}
// TODO: What validation, if any, needs to be done here?
return "corbaname:" + addr + "#" + encodeRFC2396Name(sn);
}
/**
* Resolve a bound object or context using a name
* in String form.
*
* @param n The string name of the object context. This must
* be a form parseable by to_name().
*
* @return The bound object or context.
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception org.omg.CosNaming.NamingContextPackage.CannotProceed
* @exception org.omg.CosNaming.NamingContextPackage.InvalidName
*/
public org.omg.CORBA.Object resolve_str(String n) throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName {
// this is just a simple convenience method
return resolve(to_name(n));
}
// abstract methods that are part of the NamingContext interface that need to be
// implemented by the subclasses.
/**
* Create a new context of the same type as the
* calling context.
*
* @return A new NamingContext item.
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
* @exception SystemException
*/
public abstract org.omg.CosNaming.NamingContext new_context() throws SystemException;
/**
* Destroy a context. This method should clean up
* any backing resources associated with the context.
*
* @exception org.omg.CosNaming.NamingContextPackage.NotEmpty
*/
public abstract void destroy() throws org.omg.CosNaming.NamingContextPackage.NotEmpty;
/**
* Create a list of bound objects an contexts contained
* within this context.
*
* @param how_many The count of elements to return as a BindingList.
* @param bl A holder element for returning the source binding list.
* @param bi A holder for returning a BindingIterator. Any extra
* elements not returned in the BindingList are returned
* in the BindingIterator.
*
* @exception SystemException
*/
public abstract void list(int how_many, org.omg.CosNaming.BindingListHolder bl, org.omg.CosNaming.BindingIteratorHolder bi) throws SystemException ;
// abstract methods for the sub class to implement
/**
* Resolve an object in this context (single level
* resolution).
*
* @param n The name of the target object.
* @param type A type holder for returning the bound object type
* information.
*
* @return The bound object. Returns null if the object does not
* exist in the context.
* @exception SystemException
*/
protected abstract org.omg.CORBA.Object resolveObject(NameComponent n, BindingTypeHolder type) throws SystemException;
/**
* Bind an object into the current context. This can
* be either an object or a naming context.
*
* @param n The single-level name of the target object.
* @param obj The object or context to be bound.
* @param type
*
* @exception SystemException
*/
protected abstract void bindObject(NameComponent n, org.omg.CORBA.Object obj, BindingTypeHolder type) throws SystemException;
/**
* Unbind an object from the current context.
*
* @param n The name of the target object (single level).
*
* @return The object associated with the binding. Returns null
* if there was no binding currently associated with this
* name.
* @exception SystemException
*/
protected abstract org.omg.CORBA.Object unbindObject(NameComponent n) throws SystemException;
// implementation specific routines
/**
* Resolve a name to a context object stored that has
* already been stored in this context. Throws an exception
* if the name cannot be resolved or if the resolved
* object is not a naming context.
*
* @param name The target name.
*
* @return The resolved NamingContext object.
* @exception org.omg.CosNaming.NamingContextPackage.NotFound
*/
protected synchronized NamingContext resolveContext(NameComponent name) throws org.omg.CosNaming.NamingContextPackage.NotFound {
BindingTypeHolder type = new BindingTypeHolder();
// Resolve this to an object. We must be able to resolve this.
org.omg.CORBA.Object resolvedReference = resolveObject(name, type);
if (resolvedReference == null) {
throw new NotFound(NotFoundReason.missing_node, new NameComponent[] { name });
}
// it has to resolve to a naming context
if (type.value.value() != BindingType._ncontext) {
throw new NotFound(NotFoundReason.not_context, new NameComponent[] { name });
}
// in theory, this is a naming context. Narrow it an return. Any
// errors just become a NotFound exception
try {
return NamingContextHelper.narrow(resolvedReference);
} catch (org.omg.CORBA.BAD_PARAM ex) {
throw new NotFound(NotFoundReason.not_context, new NameComponent[] { name });
}
}
/**
* Extract the tail portion of a name. This is used
* to strip off the first name element so we can recurse
* on the name resolutions with a resolved context.
*
* @param name The current name array (this MUST have 2 or more
* elements).
*
* @return An array of NameComponent items that is one element
* smaller than the argument array, with the elements
* shifted over.
*/
protected NameComponent[] extractSubName(NameComponent[] name) {
NameComponent[] subName = new NameComponent[name.length - 1];
System.arraycopy(name, 1, subName, 0, name.length - 1);
return subName;
}
/**
* Perform common name validity checking.
*
* @param n The NameComponent array to check.
*
* @exception InvalidName
*/
protected void validateName(NameComponent[] n) throws InvalidName {
// perform various name validations
if (n == null) {
throw new BAD_PARAM(MinorCodes.MinorObjectIsNull, CompletionStatus.COMPLETED_NO);
}
// Valid name?
if (n.length < 1) {
throw new InvalidName();
}
// we have at least one name, so validate the toplevel item
NameComponent name = n[0];
// more name validation
if (name.id.length() == 0 && name.kind.length() == 0) {
throw new InvalidName();
}
}
/**
* Convert a NameComponent item into a string form,
* appending it to a StringBuffer.
*
* @param name The source NameComponent.
* @param out The StringBuffer location used to store the name
* value (appended to the end).
*/
protected void nameToString(NameComponent name, StringBuffer out) {
// if the id is null, then we base off of the kind.
if (name.id == null || name.id.length() == 0) {
out.append(".");
// true null name element? That displays as a "."
if (name.kind != null && name.kind.length() != 0) {
escapeName(name.kind, out);
}
}
else {
// escape the name
escapeName(name.id, out);
// have a kind qualifier to add on?
if (name.kind != null && name.kind.length() != 0) {
out.append(".");
escapeName(name.kind, out);
}
}
}
/**
* Process a name or kind element of a NameComponent,
* adding escape characters for '.' or '/' characters
* that might appear in the name.
*
* @param name The name element to process.
* @param out The StringBuffer to copy the escaped name into.
*/
protected void escapeName(String name, StringBuffer out) {
// no characters requiring escapes (common)?
// use this directly
if (name.indexOf('.') == -1 && name.indexOf('/') == -1) {
out.append(name);
}
else {
// scan the string adding the escapes
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == '.' || ch == '/') {
out.append('/');
}
out.append(ch);
}
}
}
/**
* Perform RFC 2396 escape encoding of a name value.
*
* @param name The input name value.
*
* @return An encoded name, with special characters converted
* into a hex encoded value.
*/
protected String encodeRFC2396Name(String name) {
StringBuffer value = new StringBuffer();
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
// Alphanumerics and the "acceptable" set of special characters just get copied
// without encoding.
if (Character.isLetterOrDigit(ch) || nonEscaped.indexOf(ch) != -1) {
value.append(ch);
}
else {
// this gets converted into a hex value, marked by "%".
value.append('%');
value.append(Integer.toHexString((int)ch));
}
}
return value.toString();
}
/**
* Test if debug logging is currently available.
*
* @return True if debug level (FINE) logging is currently turned on.
*/
protected boolean isDebugEnabled() {
return logger.isLoggable(Level.FINE);
}
/**
* Log a line of debug output
*
* @param message The message to log
*/
protected void debug(String message) {
logger.fine(message);
}
/**
* Log the name components passed in for a request.
*
* @param message A message describing the request context.
* @param n The array of name components.
*/
protected void logNameComponent(String message, NameComponent[] n) {
if (isDebugEnabled()) {
debug(message);
for (int i = 0; i < n.length; i++) {
debug(" NameComponent " + i + " id=" + n[i].id + " kind=" + n[i].kind);
}
}
}
}