/* * Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jndi.toolkit.dir; import javax.naming.*; import javax.naming.directory.*; import javax.naming.spi.*; import java.util.*; /** * A sample service provider that implements a hierarchical directory in memory. * Every operation begins by doing a lookup on the name passed to it and then * calls a corresponding "do" on the result of the lookup. The * "do" does the work without any further resolution (it assumes * that it is the target context). */ public class HierMemDirCtx implements DirContext { static private final boolean debug = false; private static final NameParser defaultParser = new HierarchicalNameParser(); protected Hashtable myEnv; protected Hashtable bindings; protected Attributes attrs; protected boolean ignoreCase = false; protected NamingException readOnlyEx = null; protected NameParser myParser = defaultParser; private boolean alwaysUseFactory; public void close() throws NamingException { myEnv = null; bindings = null; attrs = null; } public String getNameInNamespace() throws NamingException { throw new OperationNotSupportedException( "Cannot determine full name"); } public HierMemDirCtx() { this(null, false, false); } public HierMemDirCtx(boolean ignoreCase) { this(null, ignoreCase, false); } public HierMemDirCtx(Hashtable environment, boolean ignoreCase) { this(environment, ignoreCase, false); } protected HierMemDirCtx(Hashtable environment, boolean ignoreCase, boolean useFac) { myEnv = environment; this.ignoreCase = ignoreCase; init(); this.alwaysUseFactory = useFac; } private void init() { attrs = new BasicAttributes(ignoreCase); bindings = new Hashtable(11, 0.75f); } public Object lookup(String name) throws NamingException { return lookup(myParser.parse(name)); } public Object lookup(Name name) throws NamingException { return doLookup(name, alwaysUseFactory); } public Object doLookup(Name name, boolean useFactory) throws NamingException { Object target = null; name = canonizeName(name); switch(name.size()) { case 0: // name is empty, caller wants this object target = this; break; case 1: // name is atomic, caller wants one of this object's bindings target = bindings.get(name); break; default: // name is compound, delegate to child context HierMemDirCtx ctx = (HierMemDirCtx)bindings.get(name.getPrefix(1)); if(ctx == null) { target = null; } else { target = ctx.doLookup(name.getSuffix(1), false); } break; } if(target == null) { throw new NameNotFoundException(name.toString()); } if (useFactory) { try { return DirectoryManager.getObjectInstance(target, name, this, myEnv, (target instanceof HierMemDirCtx) ? ((HierMemDirCtx)target).attrs : null); } catch (NamingException e) { throw e; } catch (Exception e) { NamingException e2 = new NamingException( "Problem calling getObjectInstance"); e2.setRootCause(e); throw e2; } } else { return target; } } public void bind(String name, Object obj) throws NamingException { bind(myParser.parse(name), obj); } public void bind(Name name, Object obj) throws NamingException { doBind(name, obj, null, alwaysUseFactory); } public void bind(String name, Object obj, Attributes attrs) throws NamingException { bind(myParser.parse(name), obj, attrs); } public void bind(Name name, Object obj, Attributes attrs) throws NamingException { doBind(name, obj, attrs, alwaysUseFactory); } protected void doBind(Name name, Object obj, Attributes attrs, boolean useFactory) throws NamingException { if (name.isEmpty()) { throw new InvalidNameException("Cannot bind empty name"); } if (useFactory) { DirStateFactory.Result res = DirectoryManager.getStateToBind( obj, name, this, myEnv, attrs); obj = res.getObject(); attrs = res.getAttributes(); } HierMemDirCtx ctx= (HierMemDirCtx) doLookup(getInternalName(name), false); ctx.doBindAux(getLeafName(name), obj); if (attrs != null && attrs.size() > 0) { modifyAttributes(name, ADD_ATTRIBUTE, attrs); } } protected void doBindAux(Name name, Object obj) throws NamingException { if (readOnlyEx != null) { throw (NamingException) readOnlyEx.fillInStackTrace(); } if (bindings.get(name) != null) { throw new NameAlreadyBoundException(name.toString()); } if(obj instanceof HierMemDirCtx) { bindings.put(name, obj); } else { throw new SchemaViolationException( "This context only supports binding objects of it's own kind"); } } public void rebind(String name, Object obj) throws NamingException { rebind(myParser.parse(name), obj); } public void rebind(Name name, Object obj) throws NamingException { doRebind(name, obj, null, alwaysUseFactory); } public void rebind(String name, Object obj, Attributes attrs) throws NamingException { rebind(myParser.parse(name), obj, attrs); } public void rebind(Name name, Object obj, Attributes attrs) throws NamingException { doRebind(name, obj, attrs, alwaysUseFactory); } protected void doRebind(Name name, Object obj, Attributes attrs, boolean useFactory) throws NamingException { if (name.isEmpty()) { throw new InvalidNameException("Cannot rebind empty name"); } if (useFactory) { DirStateFactory.Result res = DirectoryManager.getStateToBind( obj, name, this, myEnv, attrs); obj = res.getObject(); attrs = res.getAttributes(); } HierMemDirCtx ctx= (HierMemDirCtx) doLookup(getInternalName(name), false); ctx.doRebindAux(getLeafName(name), obj); // // attrs == null -> use attrs from obj // attrs != null -> use attrs // // %%% Strictly speaking, when attrs is non-null, we should // take the explicit step of removing obj's attrs. // We don't do that currently. if (attrs != null && attrs.size() > 0) { modifyAttributes(name, ADD_ATTRIBUTE, attrs); } } protected void doRebindAux(Name name, Object obj) throws NamingException { if (readOnlyEx != null) { throw (NamingException) readOnlyEx.fillInStackTrace(); } if(obj instanceof HierMemDirCtx) { bindings.put(name, obj); } else { throw new SchemaViolationException( "This context only supports binding objects of it's own kind"); } } public void unbind(String name) throws NamingException { unbind(myParser.parse(name)); } public void unbind(Name name) throws NamingException { if (name.isEmpty()) { throw new InvalidNameException("Cannot unbind empty name"); } else { HierMemDirCtx ctx= (HierMemDirCtx) doLookup(getInternalName(name), false); ctx.doUnbind(getLeafName(name)); } } protected void doUnbind(Name name) throws NamingException { if (readOnlyEx != null) { throw (NamingException) readOnlyEx.fillInStackTrace(); } bindings.remove(name); // attrs will also be removed along with ctx } public void rename(String oldname, String newname) throws NamingException { rename(myParser.parse(oldname), myParser.parse(newname)); } public void rename(Name oldname, Name newname) throws NamingException { if(newname.isEmpty() || oldname.isEmpty()) { throw new InvalidNameException("Cannot rename empty name"); } if (!getInternalName(newname).equals(getInternalName(oldname))) { throw new InvalidNameException("Cannot rename across contexts"); } HierMemDirCtx ctx = (HierMemDirCtx) doLookup(getInternalName(newname), false); ctx.doRename(getLeafName(oldname), getLeafName(newname)); } protected void doRename(Name oldname, Name newname) throws NamingException { if (readOnlyEx != null) { throw (NamingException) readOnlyEx.fillInStackTrace(); } oldname = canonizeName(oldname); newname = canonizeName(newname); // Check if new name exists if (bindings.get(newname) != null) { throw new NameAlreadyBoundException(newname.toString()); } // Check if old name is bound Object oldBinding = bindings.remove(oldname); if (oldBinding == null) { throw new NameNotFoundException(oldname.toString()); } bindings.put(newname, oldBinding); } public NamingEnumeration list(String name) throws NamingException { return list(myParser.parse(name)); } public NamingEnumeration list(Name name) throws NamingException { HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); return ctx.doList(); } protected NamingEnumeration doList () throws NamingException { return new FlatNames(bindings.keys()); } public NamingEnumeration listBindings(String name) throws NamingException { return listBindings(myParser.parse(name)); } public NamingEnumeration listBindings(Name name) throws NamingException { HierMemDirCtx ctx = (HierMemDirCtx)doLookup(name, false); return ctx.doListBindings(alwaysUseFactory); } protected NamingEnumeration doListBindings(boolean useFactory) throws NamingException { return new FlatBindings(bindings, myEnv, useFactory); } public void destroySubcontext(String name) throws NamingException { destroySubcontext(myParser.parse(name)); } public void destroySubcontext(Name name) throws NamingException { HierMemDirCtx ctx = (HierMemDirCtx) doLookup(getInternalName(name), false); ctx.doDestroySubcontext(getLeafName(name)); } protected void doDestroySubcontext(Name name) throws NamingException { if (readOnlyEx != null) { throw (NamingException) readOnlyEx.fillInStackTrace(); } name = canonizeName(name); bindings.remove(name); } public Context createSubcontext(String name) throws NamingException { return createSubcontext(myParser.parse(name)); } public Context createSubcontext(Name name) throws NamingException { return createSubcontext(name, null); } public DirContext createSubcontext(String name, Attributes attrs) throws NamingException { return createSubcontext(myParser.parse(name), attrs); } public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException { HierMemDirCtx ctx = (HierMemDirCtx) doLookup(getInternalName(name), false); return ctx.doCreateSubcontext(getLeafName(name), attrs); } protected DirContext doCreateSubcontext(Name name, Attributes attrs) throws NamingException { if (readOnlyEx != null) { throw (NamingException) readOnlyEx.fillInStackTrace(); } name = canonizeName(name); if (bindings.get(name) != null) { throw new NameAlreadyBoundException(name.toString()); } HierMemDirCtx newCtx = createNewCtx(); bindings.put(name, newCtx); if(attrs != null) { newCtx.modifyAttributes("", ADD_ATTRIBUTE, attrs); } return newCtx; } public Object lookupLink(String name) throws NamingException { // This context does not treat links specially return lookupLink(myParser.parse(name)); } public Object lookupLink(Name name) throws NamingException { // Flat namespace; no federation; just call string version return lookup(name); } public NameParser getNameParser(String name) throws NamingException { return myParser; } public NameParser getNameParser(Name name) throws NamingException { return myParser; } public String composeName(String name, String prefix) throws NamingException { Name result = composeName(new CompositeName(name), new CompositeName(prefix)); return result.toString(); } public Name composeName(Name name, Name prefix) throws NamingException { name = canonizeName(name); prefix = canonizeName(prefix); Name result = (Name)(prefix.clone()); result.addAll(name); return result; } public Object addToEnvironment(String propName, Object propVal) throws NamingException { myEnv = (myEnv == null) ? new Hashtable(11, 0.75f) : (Hashtable)myEnv.clone(); return myEnv.put(propName, propVal); } public Object removeFromEnvironment(String propName) throws NamingException { if (myEnv == null) return null; myEnv = (Hashtable)myEnv.clone(); return myEnv.remove(propName); } public Hashtable getEnvironment() throws NamingException { if (myEnv == null) { return new Hashtable(5, 0.75f); } else { return (Hashtable)myEnv.clone(); } } public Attributes getAttributes(String name) throws NamingException { return getAttributes(myParser.parse(name)); } public Attributes getAttributes(Name name) throws NamingException { HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); return ctx.doGetAttributes(); } protected Attributes doGetAttributes() throws NamingException { return (Attributes)attrs.clone(); } public Attributes getAttributes(String name, String[] attrIds) throws NamingException { return getAttributes(myParser.parse(name), attrIds); } public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); return ctx.doGetAttributes(attrIds); } protected Attributes doGetAttributes(String[] attrIds) throws NamingException { if (attrIds == null) { return doGetAttributes(); } Attributes attrs = new BasicAttributes(ignoreCase); Attribute attr = null; for(int i=0; i 0; i--) { hashValue = (hashValue * 37) + val[off++]; } } return hashValue; } public Name getPrefix(int posn) { Enumeration comps = super.getPrefix(posn).getAll(); return (new HierarchicalName(comps, mySyntax)); } public Name getSuffix(int posn) { Enumeration comps = super.getSuffix(posn).getAll(); return (new HierarchicalName(comps, mySyntax)); } public Object clone() { return (new HierarchicalName(getAll(), mySyntax)); } private static final long serialVersionUID = -6717336834584573168L; } // This is the default name parser (used if setNameParser is not called) final class HierarchicalNameParser implements NameParser { static final Properties mySyntax = new Properties(); static { mySyntax.put("jndi.syntax.direction", "left_to_right"); mySyntax.put("jndi.syntax.separator", "/"); mySyntax.put("jndi.syntax.ignorecase", "true"); mySyntax.put("jndi.syntax.escape", "\\"); mySyntax.put("jndi.syntax.beginquote", "\""); //mySyntax.put("jndi.syntax.separator.ava", "+"); //mySyntax.put("jndi.syntax.separator.typeval", "="); mySyntax.put("jndi.syntax.trimblanks", "false"); }; public Name parse(String name) throws NamingException { return new HierarchicalName(name, mySyntax); } }