Modified: incubator/ode/scratch/pxe-iapi/utils/pom.xml URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/pom.xml?rev=426231&r1=426230&r2=426231&view=diff ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/pom.xml (original) +++ incubator/ode/scratch/pxe-iapi/utils/pom.xml Thu Jul 27 13:45:49 2006 @@ -33,5 +33,11 @@ <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> </dependency> + + <dependency> + <groupId>wsdl4j</groupId> + <artifactId>wsdl4j</artifactId> + </dependency> + </dependencies> </project>
Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ImportingWsdlLocator.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ImportingWsdlLocator.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ImportingWsdlLocator.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ImportingWsdlLocator.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,113 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ +package com.fs.utils.rr; + +import java.net.URI; +import java.net.URISyntaxException; + +import javax.wsdl.xml.WSDLLocator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.InputSource; + +/** + * Base class providing basic "import" functionality required in + * a [EMAIL PROTECTED] javax.wsdl.xml.WSDLLocator} object. + */ +abstract class ImportingWsdlLocator implements WSDLLocator { + private static Log __log = LogFactory.getLog(ImportingWsdlLocator.class); + + private URI _baseURI; + private URI _latestImportUri; + + ImportingWsdlLocator(URI baseURI) { + if (baseURI == null) + throw new IllegalArgumentException("baseURI must not be null!"); + + _baseURI = baseURI; + } + + /** + * Implementation of [EMAIL PROTECTED] WSDLLocator#getBaseInputSource} that + * simply defers to [EMAIL PROTECTED] #resolveURI(String, String, java.net.URI)} )}. + * @return an [EMAIL PROTECTED] InputSource} to the <em>base</em> WSDL object + */ + public InputSource getBaseInputSource() { + // Note: WSDL4J 1.5.1 will not check for a null result, so if + // a resource is not found, NullPointerException will occur. + return resolveURI(null, _baseURI.toASCIIString(), _baseURI); + } + + /** + * @see WSDLLocator#getBaseURI + */ + public String getBaseURI() { + return _baseURI.toASCIIString(); + } + + /** + * Implementation of [EMAIL PROTECTED] WSDLLocator#getImportInputSource} that + * defers to [EMAIL PROTECTED] #resolveURI} after having first attempted + * to compute an absolute URL for the requested URI. The absolute + * URL is derived either from the requested URI (if it is a valid + * URL) or from a concatenation of the URI of the requesting WSDL + * object (sans any characters after the last '/') and the + * (relative) URI of the requested WSDL object. + * @param context the URI of the WSDL object requesting a + * URI + * @param location the (possibly relative) URI of the requested WSDL + * object + * @return an [EMAIL PROTECTED] InputSource} to the requested WSDL object + */ + public InputSource getImportInputSource(String context, String location) { + //String uri = context + location; + // check if location is a full URL in it'context own right + + URI loc; + try { + loc = new URI(location); + } catch (URISyntaxException e) { + __log.error("Invalid location URI " + location, e); + return null; + } + + if (!loc.isAbsolute()) + try { + loc = new URI(context).resolve(location); + } catch (URISyntaxException e) { + __log.error("Invalid context URI " + context,e); + return null; + } + + _latestImportUri = loc; + return resolveURI(context, location, loc); + } + + public String getLatestImportURI() { + return _latestImportUri == null ? null : _latestImportUri.toASCIIString(); + } + + /** + * Abstract method that does the actual resolving of URIs to the + * corresponding [EMAIL PROTECTED] InputSource} objects. This mapping may be + * completely transparrent (i.e. through the URL mechanism) or it + * may rely on some sort of caching or URI re-writing scheme. + * @param requestingURI the URI of the WSDL document that requested + * (through an <code>import</code>) some URI + * or <code>null</code> if this is a request + * for the <em>base</em> WSDL. + * @param requestedURI the (possibly relative) URI of the requested + * document + * @param uri the <code>requestedURI</code> only if it is a true + * absolute URI, otherwise a URI computed from the + * <code>requestingURI</code> and the <em>relative</em> + * <code>requestedURI</code> + * @return [EMAIL PROTECTED] InputSource} for the requested URI, or + <code>null</code> if the URI cannot be resolved. + */ + public abstract InputSource resolveURI(String requestingURI, String requestedURI, URI uri); +} Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/Messages.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/Messages.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/Messages.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/Messages.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,158 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ + +package com.fs.utils.rr; + +import com.fs.utils.msg.MessageBundle; + +/** + * Message bundle for ResourceRepository functionality. + */ +public class Messages extends MessageBundle { + + /** + * A resource was added to a repository. + * + * @param uri + * @param src + * @return Added resource [uri={0}, source={1}] + */ + public String msgAddedResource(String uri, String src) { + return this.format("Added resource [uri={0}, source={1}]", uri, src); + } + + /** + * Return a key identifying an InputStream as an entry. + * + * <InputStream> + */ + public String msgInputStream() { + return this.format("<InputStream>"); + } + + /** + * Fatal error while trying to add an unknown resource type. + * + * @param uri + * @param name + * + * Unable to add a resource of type {1} to repository for URI {0}. + */ + public String msgFatalUnknownType(String uri, String name) { + return this.format("Unable to add a resource of type {1} to repository for URI {0}.", uri, + name); + } + + /** + * A URI could not be opened. + * + * @param uri + * the URI for the resource that we were trying to load + * @param message + * a descriptive error message + * + * Unable to open stream for URI {0}: {1} + */ + public String msgUnableToOpenStream(String uri, String message) { + return this.format("Unable to open stream for URI {0}: {1}", uri, message); + } + + /** + * Report an error about a URI without a registered resource. + * + * @param uri + * the URI + * + * No resource was registered for URI {0}. + */ + public String msgFatalMissingResource(String uri) { + return this.format("No resource was registered for URI {0}."); + } + + /** + * Report an error about not being able to write to the destination. + * + * @param msg + * a descriptive error message + * + * Unable to write to output: {0} + */ + public String msgCannotWriteToOutput(String msg) { + return this.format("Unable to write to output: {0}"); + } + + /** + * Report an error that occurred while writing a resource to a repository. + * + * @param uri + * the URI + * @param message + * a descriptive error message + * + * Error adding resource at URI {0} to the repository: {1} + */ + public String msgErrorWritingResource(String uri, String message) { + return this + .format("Error adding resource at URI {0} to the repository: {1}", uri, message); + } + + /** + * Format a message about being unable to write the registry into the + * manifest. + * + * @param message + * a descriptive message about the IO error. + * + * Unable to write registry into manifest for repository: {0} + */ + public String msgErrorWritingRegistry(String message) { + return this.format("Unable to write registry into manifest for repository: {0}", message); + } + + /** + * Format a message about a non-existent working directory. + * + * @param path + * the path for the desired working directory + * + * The directory {0} does not exist (and thus is not a suitable working + * directory). + */ + public String msgWorkingDirectoryDoesNotExist(String path) { + return this.format("The directory {0} does not exist" + + " (and thus is not a suitable working directory).", path); + } + + /** + * Format a message about a working directory that is a regular file instead + * of a directory. + * + * @param path + * the path of the desired working directory + * + * The path {0} does not specify a directory (and thus is not a suitable + * working directory). + */ + public String msgWorkingDirectoryNotDirectory(String path) { + return this.format("The path {0} does not specify a directory" + + " (and thus is not a suitable working directory).", path); + } + + /** + * Format a message about a non-writable working directory. + * + * @param path + * the path of the working directory + * + * The directory {0} is not writable (and thus is not a suitable working + * directory). + */ + public String msgWorkingDirectoryNotWritable(String path) { + return this.format("The directory {0} is not writable" + + " (and thus is not a suitable working directory).", path); + } + +} Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/RepositoryWsdlLocator.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/RepositoryWsdlLocator.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/RepositoryWsdlLocator.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/RepositoryWsdlLocator.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,60 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ +package com.fs.utils.rr; + +import com.fs.utils.StreamUtils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URL; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.InputSource; + + +/** + * WsdlLocator that defers to the [EMAIL PROTECTED] ResourceRepository} for its + * resources. + */ +public class RepositoryWsdlLocator extends ImportingWsdlLocator { + private static Log __log = LogFactory.getLog(RepositoryWsdlLocator.class); + + private ResourceRepository _repository; + + public RepositoryWsdlLocator(ResourceRepository rr, URI baseUri) { + super(baseUri); + _repository = rr; + } + + /* (non-Javadoc) + * @see com.fs.utils.wsdl.ImportingWsdlLocator#resolveURI(java.lang.String, java.lang.String, java.lang.String) + */ + public InputSource resolveURI(String requestingURI, String requestedURI, URI uri) { + try { + URL url = _repository.resolveURI(uri); + + if (url == null) { + if (__log.isDebugEnabled()) + __log.debug("resource repository does not contain resource: " + url); + return null; + } + + InputSource source = new InputSource(uri.toASCIIString()); + // we read the URL's contents into memory in order to avoid + // problems with lingering file handles. + source.setByteStream(new ByteArrayInputStream(StreamUtils.read(url))); + return source; + } + catch (IOException e) { + if (__log.isDebugEnabled()) + __log.debug("error obtaining resource '" + uri + "' from repository.", e); + return null; + } + } + +} Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepository.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepository.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepository.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepository.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,45 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ +package com.fs.utils.rr; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + + +/** + * <p> + * A store for byte streams keyed to URIs. Implementations may back the repository + * with various modes of storage, e.g., file, database, cache, or "live" + * connections, although the expectation is that the store is static, i.e., a + * resource obtained from an instance will be the same no matter when/how the + * lookup is performed. + * </p> + */ +public interface ResourceRepository extends Closeable { + + /** + * <p> + * Look up a resource as a URL. The <code>URL</code> object that is returned is + * not the original URL but a URL to the internal version of the resource. For + * example, if an implementation is backed by files on disk, the URL will point to + * the file containing the resource. + * </p> + * @param uri the URI to look up. + * @return a <code>URL</code> that can be dereferenced to obtain the resource, + * or <code>null</code> if the URI cannot be resolved. + */ + public URL resolveURI(URI uri); + + boolean containsResource(URI uri); + + InputStream resourceAsStream(URI uri) throws IOException; + + void close() throws IOException; + +} Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryBuilder.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryBuilder.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryBuilder.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryBuilder.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,170 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ +package com.fs.utils.rr; + +import com.fs.utils.StreamUtils; +import com.fs.utils.XMLParserUtils; + +import java.io.*; +import java.net.URI; +import java.net.URL; +import java.util.Properties; +import java.util.StringTokenizer; + +import org.xml.sax.*; + +/** + * Builder for creating on-disk representations of [EMAIL PROTECTED] URLResourceRepository} objects. + */ +public class ResourceRepositoryBuilder { + + /** Destination <em>directory</em>. */ + private File _dest; + + /** The mapping file. */ + private File _mapFile = null; + + /** The actual uri->local resource mappings. */ + private Properties _map = new Properties(); + + + public ResourceRepositoryBuilder(File dest) throws FileNotFoundException, IOException { + _dest = dest; + _mapFile = new File(_dest, URLResourceRepository.RR_PROPERTIES); + if (!_dest.isDirectory()) + throw new FileNotFoundException(_dest.toString()); + loadMapping(); + saveMapping(); + } + + public boolean containsResource(URI uri) { + return _map.containsKey(uri.toASCIIString()); + } + + public void addURI(URI uri, InputStream is) throws IOException { + addURI(uri, createLocalName(uri), is); + } + + public void addURI(URI uri, URL url) throws IOException { + InputStream is = url.openStream(); + try { + addURI(uri, createLocalName(uri), is); + } finally { + is.close(); + } + } + + + public void addURI(URI uri, String localName, InputStream is) throws IOException{ + File f = new File(_dest, localName); + if (!f.getParentFile().exists() && !f.getParentFile().mkdirs()) + throw new IOException("unable to create directories for " + f); + + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f)); + try { + StreamUtils.copy(bos,is); + } finally { + bos.close(); + } + _map.setProperty(uri.toASCIIString(), localName); + saveMapping(); + } + + public void addURI(URI uri, InputSource source, EntityResolver resolver) throws IOException, SAXException { + String localName = createLocalName(uri); + File f = new File(_dest, localName); + if (!f.getParentFile().exists() && !f.getParentFile().mkdirs()) + throw new IOException("unable to create directories for " + f); + + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f)); + ContentHandler handler = XMLParserUtils.getXercesSerializer(bos); + XMLReader reader = XMLParserUtils.getXMLReader(); + reader.setEntityResolver(resolver); + reader.setContentHandler(handler); + try { + reader.parse(source); + } finally { + bos.close(); + } + + _map.setProperty(uri.toASCIIString(), localName); + saveMapping(); + } + + public ResourceRepository toResourceRepository() throws ResourceRepositoryException { + return new URLResourceRepository(_mapFile.toURI()); + } + + private void loadMapping() throws IOException { + if (_mapFile.exists()) { + InputStream is = new BufferedInputStream(new FileInputStream(_mapFile)); + try { + _map.load(is); + } finally { + is.close(); + } + } + } + + private void saveMapping() throws IOException { + OutputStream os = new BufferedOutputStream(new FileOutputStream(_mapFile)); + try { + _map.store(os, "PXE Resource Repository"); + } finally { + os.close(); + } + } + + private String createLocalName(URI uri) { + String prefix = uri.getPath(); + if (prefix == null) { + prefix = "resource"; + } + else { + StringTokenizer stok = new StringTokenizer(prefix, ":/",false); + while (stok.hasMoreTokens()) { + prefix = stok.nextToken(); + } + prefix = prefix.trim(); + if (prefix.length() == 0) { + prefix = "resource"; + } + } + + int i = 0; + String path = prefix+i; + + // Lets just try to use the path component of the URI, + // possibly with an index appended. + while(_map.containsValue(path) && i < Integer.MAX_VALUE) { + path = prefix + ++i; + } + + // If we ran out of integers (hm.... thats a lot of resources + // but better safe than sorry), try a system generated unique + // name. + if (_map.containsValue(path)) { + throw new RuntimeException("Too many resources."); + } + + return path; + } + + public void removeURI(URI uri) throws IOException { + _map.remove(uri.toASCIIString()); + saveMapping(); + } + + public void addAlias(URI from, URI to) throws IOException { + String localName = _map.getProperty(to.toASCIIString()); + if (localName == null) { + throw new FileNotFoundException(to.toASCIIString()); + } + _map.setProperty(from.toASCIIString(),localName); + saveMapping(); + } + +} Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryException.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryException.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryException.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/ResourceRepositoryException.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,25 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ +package com.fs.utils.rr; + +/** + * Resource repository exception. + */ +public class ResourceRepositoryException extends Exception { + + public ResourceRepositoryException(String msg) { + super(msg); + } + + public ResourceRepositoryException(Throwable cause) { + super(cause); + } + + public ResourceRepositoryException(String msg, Throwable cause) { + super(msg, cause); + } + +} Added: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/URLResourceRepository.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/URLResourceRepository.java?rev=426231&view=auto ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/URLResourceRepository.java (added) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/rr/URLResourceRepository.java Thu Jul 27 13:45:49 2006 @@ -0,0 +1,142 @@ +/* + * File: $RCSfile$ + * Copyright: (C) 1999-2005 FiveSight Technologies Inc. + * + */ +package com.fs.utils.rr; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.*; +import java.util.Map.Entry; + + +/** + * [EMAIL PROTECTED] ResourceRepository} implementation that uses a base URL and + * a [EMAIL PROTECTED] Properties} file to locate resources. + */ +public class URLResourceRepository implements ResourceRepository { + static final String RR_PROPERTIES = "rr.properties"; + + private final Map<InputStream, Object> _streams = new WeakHashMap<InputStream, Object>(); + private final Properties _mappings = new Properties(); + private boolean _open = false; + private URI _baseURI; + + public URLResourceRepository(URI baseURL) throws ResourceRepositoryException { + _baseURI = baseURL; + + URI rrproperties = _baseURI.resolve(RR_PROPERTIES); + InputStream is = null; + try { + is = rrproperties.toURL().openStream(); + _mappings.load(is); + _open = true; + } + catch (IOException e) { + throw new ResourceRepositoryException("error opening URL resource repository at " + baseURL, e); + } + finally { + if (is != null) { + try { + is.close(); + } + catch (IOException e) { + // ignore. + } + } + } + } + + protected void finalize() throws Throwable { + this.close(); + super.finalize(); + } + + public synchronized void close() throws IOException { + // close all registered and not-yet-GC'ed streams + for (InputStream s : _streams.keySet()) { + s.close(); + } + _streams.clear(); + _open = false; + } + + public URL resolveURI(URI uri) { + this.checkOpen(); + + String resource = _mappings.getProperty(uri.toASCIIString()); + if (resource == null) { + return null; + } + + try { + URI resolved = _baseURI.resolve(resource); + return resolved.toURL(); + } catch (IOException e) { + return null; + } + } + + public InputStream resourceAsStream(URI uri) throws IOException { + this.checkOpen(); + + // check resource availability + URL url = this.resolveURI(uri); + if (url == null) { + return null; + } + + // if it exists, open a stream for reading + InputStream stream = url.openStream(); + + // ...and register the stream for later closing + synchronized (_streams) { + _streams.put(stream, null); + } + + return stream; + } + + public boolean containsResource(URI uri) { + this.checkOpen(); + return _mappings.containsKey(uri.toASCIIString()); + } + + public URI getBaseURL() { + this.checkOpen(); + return _baseURI; + } + + public Map<URI, String> getTableOfContents() { + this.checkOpen(); + + HashMap<URI, String> ret = new HashMap<URI, String>(); + for (Iterator<Entry<Object, Object>> i = _mappings.entrySet().iterator();i.hasNext();) { + Map.Entry me = i.next(); + URI uri; + try { + uri = new URI((String)me.getKey()); + } catch (URISyntaxException ex) { + // This is rather unexpected. + throw new IllegalStateException(ex); + } + ret.put(uri, (String)me.getValue()); + } + return ret; + } + + public String toString() { + return "{RR on " + _baseURI + "}"; + } + + private void checkOpen() { + if (!_open) { + throw new IllegalStateException("ResourceRepository is not opened!"); + } + } + +} Modified: incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/xml/capture/XmlSchemaTracker.java URL: http://svn.apache.org/viewvc/incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/xml/capture/XmlSchemaTracker.java?rev=426231&r1=426230&r2=426231&view=diff ============================================================================== --- incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/xml/capture/XmlSchemaTracker.java (original) +++ incubator/ode/scratch/pxe-iapi/utils/src/main/java/com/fs/utils/xml/capture/XmlSchemaTracker.java Thu Jul 27 13:45:49 2006 @@ -21,14 +21,9 @@ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { if (uri != null && uri.equals(NS) && (localName.equals("import") || localName.equals("include"))) { String loc = atts.getValue("schemaLocation"); - // If we don't specify a location, we assume that the namespace - // is also the location. - if (loc == null) - loc = atts.getValue("namespace"); - __log.debug("found reference element " + uri + "@" + localName + "-->" +loc); - addReference(loc); + if (loc != null) addReference(loc); } } }
