001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.graph.properties.basic;
023
024 import java.text.DecimalFormat;
025 import java.util.Collections;
026 import java.util.HashMap;
027 import java.util.HashSet;
028 import java.util.Map;
029 import java.util.Set;
030 import java.util.concurrent.locks.Lock;
031 import java.util.concurrent.locks.ReadWriteLock;
032 import java.util.concurrent.locks.ReentrantReadWriteLock;
033 import net.jcip.annotations.GuardedBy;
034 import net.jcip.annotations.ThreadSafe;
035 import org.jboss.dna.common.util.CheckArg;
036 import org.jboss.dna.graph.properties.NamespaceRegistry;
037
038 /**
039 * @author Randall Hauch
040 */
041 @ThreadSafe
042 public class BasicNamespaceRegistry implements NamespaceRegistry {
043
044 public static final String DEFAULT_NAMESPACE_URI = "";
045 public static final String DEFAULT_PREFIX_TEMPLATE = "ns##000";
046 public static final String DEFAULT_PREFIX_NUMBER_FORMAT = "##000";
047
048 private final ReadWriteLock registryLock = new ReentrantReadWriteLock();
049 private final Map<String, String> namespacesByPrefix = new HashMap<String, String>();
050 private final Map<String, String> prefixesByNamespace = new HashMap<String, String>();
051 private String generatedPrefixTemplate = DEFAULT_PREFIX_TEMPLATE;
052 private int nextGeneratedPrefixNumber = 1;
053
054 /**
055 *
056 */
057 public BasicNamespaceRegistry() {
058 this(DEFAULT_NAMESPACE_URI);
059 }
060
061 /**
062 * @param defaultNamespaceUri the namespace URI to use for the default prefix
063 */
064 public BasicNamespaceRegistry( final String defaultNamespaceUri ) {
065 register("", defaultNamespaceUri);
066 }
067
068 /**
069 * @return prefixTemplate
070 */
071 public String getGeneratedPrefixTemplate() {
072 Lock lock = this.registryLock.readLock();
073 try {
074 lock.lock();
075 return this.generatedPrefixTemplate;
076 } finally {
077 lock.unlock();
078 }
079 }
080
081 /**
082 * @param prefixTemplate Sets prefixTemplate to the specified value.
083 */
084 public void setGeneratedPrefixTemplate( String prefixTemplate ) {
085 if (prefixTemplate == null) prefixTemplate = DEFAULT_PREFIX_TEMPLATE;
086 Lock lock = this.registryLock.writeLock();
087 try {
088 lock.lock();
089 this.generatedPrefixTemplate = prefixTemplate;
090 } finally {
091 lock.unlock();
092 }
093 }
094
095 /**
096 * {@inheritDoc}
097 */
098 public String getNamespaceForPrefix( String prefix ) {
099 CheckArg.isNotNull(prefix, "prefix");
100 Lock lock = this.registryLock.readLock();
101 try {
102 lock.lock();
103 return this.namespacesByPrefix.get(prefix);
104 } finally {
105 lock.unlock();
106 }
107 }
108
109 /**
110 * {@inheritDoc}
111 */
112 public String getPrefixForNamespaceUri( String namespaceUri,
113 boolean generateIfMissing ) {
114 CheckArg.isNotNull(namespaceUri, "namespaceUri");
115 String prefix = null;
116 Lock lock = this.registryLock.readLock();
117 try {
118 lock.lock();
119 prefix = this.prefixesByNamespace.get(namespaceUri);
120 } finally {
121 lock.unlock();
122 }
123 if (prefix == null && generateIfMissing) {
124 // Get a write lock ...
125 lock = this.registryLock.writeLock();
126 try {
127 lock.lock();
128 // Since we got a new lock, we need to check again ...
129 prefix = this.prefixesByNamespace.get(namespaceUri);
130 if (prefix == null) {
131 // Now we can genereate a prefix and register it ...
132 prefix = this.generatePrefix();
133 this.register(prefix, namespaceUri);
134 }
135 return prefix;
136 } finally {
137 lock.unlock();
138 }
139 }
140 return prefix;
141 }
142
143 /**
144 * {@inheritDoc}
145 */
146 public boolean isRegisteredNamespaceUri( String namespaceUri ) {
147 CheckArg.isNotNull(namespaceUri, "namespaceUri");
148 Lock lock = this.registryLock.readLock();
149 try {
150 lock.lock();
151 return this.prefixesByNamespace.containsKey(namespaceUri);
152 } finally {
153 lock.unlock();
154 }
155 }
156
157 /**
158 * {@inheritDoc}
159 */
160 public String getDefaultNamespaceUri() {
161 Lock lock = this.registryLock.readLock();
162 try {
163 lock.lock();
164 return this.namespacesByPrefix.get("");
165 } finally {
166 lock.unlock();
167 }
168 }
169
170 /**
171 * {@inheritDoc}
172 */
173 public String register( String prefix,
174 String namespaceUri ) {
175 CheckArg.isNotNull(namespaceUri, "namespaceUri");
176 String previousNamespaceForPrefix = null;
177 namespaceUri = namespaceUri.trim();
178 Lock lock = this.registryLock.writeLock();
179 try {
180 lock.lock();
181 if (prefix == null) prefix = generatePrefix();
182 prefix = prefix.trim();
183 previousNamespaceForPrefix = this.namespacesByPrefix.put(prefix, namespaceUri);
184 String previousPrefix = this.prefixesByNamespace.put(namespaceUri, prefix);
185 if (previousPrefix != null && !previousPrefix.equals(prefix)) {
186 this.namespacesByPrefix.remove(previousPrefix);
187 }
188 if (previousNamespaceForPrefix != null && !previousNamespaceForPrefix.equals(namespaceUri)) {
189 this.prefixesByNamespace.remove(previousNamespaceForPrefix);
190 }
191 } finally {
192 lock.unlock();
193 }
194 return previousNamespaceForPrefix;
195 }
196
197 /**
198 * {@inheritDoc}
199 */
200 public Set<String> getRegisteredNamespaceUris() {
201 Set<String> result = new HashSet<String>();
202 Lock lock = this.registryLock.readLock();
203 try {
204 lock.lock();
205 result.addAll(this.prefixesByNamespace.keySet());
206 } finally {
207 lock.unlock();
208 }
209 return Collections.unmodifiableSet(result);
210 }
211
212 @GuardedBy( "registryLock" )
213 protected String generatePrefix() {
214 DecimalFormat formatter = new DecimalFormat(this.generatedPrefixTemplate);
215 return formatter.format(nextGeneratedPrefixNumber++);
216 }
217
218 }