1 /* 2 * Copyright 2011-2013 smartics, Kronseder & Reiner GmbH 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package de.smartics.util.lang.classpath; 17 18 import java.io.IOException; 19 import java.io.InputStream; 20 import java.net.MalformedURLException; 21 import java.net.URL; 22 import java.util.Enumeration; 23 24 import org.apache.commons.lang.ObjectUtils; 25 26 import de.smartics.util.lang.Arg; 27 28 /** 29 * A constraint on resources to be loaded from the class path. 30 */ 31 public final class ClassPathContext 32 { 33 // ********************************* Fields ********************************* 34 35 // --- constants ------------------------------------------------------------ 36 37 // --- members -------------------------------------------------------------- 38 39 /** 40 * The class loader to load the directory listings. 41 */ 42 private final ClassLoader classLoader; 43 44 /** 45 * Selects the archive root to load from. 46 */ 47 private final String archiveRoot; 48 49 // ****************************** Initializer ******************************* 50 51 // ****************************** Constructors ****************************** 52 53 /** 54 * Default constructor. 55 * 56 * @param classLoader the class loader to load the directory listings. 57 * @param archiveRoot the value for archiveRoot. 58 * @throws NullPointerException if {@code classLoader} is <code>null</code>. 59 */ 60 public ClassPathContext(final ClassLoader classLoader, 61 final String archiveRoot) throws NullPointerException 62 { 63 Arg.checkNotNull("classLoader", classLoader); 64 65 this.classLoader = classLoader; 66 this.archiveRoot = archiveRoot; 67 } 68 69 // ****************************** Inner Classes ***************************** 70 71 // ********************************* Methods ******************************** 72 73 // --- init ----------------------------------------------------------------- 74 75 // --- get&set -------------------------------------------------------------- 76 77 // --- business ------------------------------------------------------------- 78 79 /** 80 * Constructs the URL to the resource. 81 * 82 * @param resource the resource whose URL is requested. 83 * @return the URL to the resource or <code>null</code> if the resource cannot 84 * be found on the class path. 85 */ 86 public URL getResource(final String resource) 87 { 88 if (archiveRoot == null) 89 { 90 return classLoader.getResource(resource); 91 } 92 93 // TODO: maybe we should simply construct the URL? 94 try 95 { 96 for (final Enumeration<URL> en = classLoader.getResources(resource); en 97 .hasMoreElements();) 98 { 99 final URL current = en.nextElement(); 100 final String urlString = current.toExternalForm(); 101 if (urlString.startsWith(archiveRoot)) 102 { 103 return current; 104 } 105 } 106 } 107 catch (final IOException e) 108 { 109 // return null 110 } 111 return null; 112 } 113 114 /** 115 * Opens the stream to the resource. 116 * 117 * @param resource the resource whose stream is requested. 118 * @return the stream to the resource or <code>null</code> if the resource 119 * cannot be found on the class path. If a stream is returned, the 120 * client is responsible to close that stream. 121 */ 122 public InputStream getResourceAsStream(final String resource) 123 { 124 final URL url = getResource(resource); 125 if (url != null) 126 { 127 try 128 { 129 return url.openStream(); 130 } 131 catch (final IOException e) 132 { 133 // return null; 134 } 135 } 136 return null; 137 } 138 139 /** 140 * Constructs the URL to the resource. 141 * 142 * @param resource the resource whose URL is requested. 143 * @return the constructed URL. 144 * @throws IllegalArgumentException if the URL to the resource cannot be 145 * constructed. 146 */ 147 public URL createUrl(final String resource) throws IllegalArgumentException 148 { 149 try 150 { 151 final String urlString = 152 (archiveRoot != null ? archiveRoot : "") + resource; 153 return new URL(urlString); 154 } 155 catch (final MalformedURLException e) 156 { 157 throw new IllegalArgumentException("Cannot construct URL with resource '" 158 + resource + "'.", e); 159 } 160 } 161 162 // --- object basics -------------------------------------------------------- 163 164 /** 165 * Returns the hash code of the object. 166 * 167 * @return the hash code. 168 */ 169 @Override 170 public int hashCode() 171 { 172 return ObjectUtils.hashCode(archiveRoot); 173 } 174 175 /** 176 * Returns <code>true</code> if the given object is semantically equal to the 177 * given object, <code>false</code> otherwise. 178 * 179 * @param object the instance to compare to. 180 * @return <code>true</code> if the given object is semantically equal to the 181 * given object, <code>false</code> otherwise. 182 */ 183 @Override 184 public boolean equals(final Object object) 185 { 186 if (this == object) 187 { 188 return true; 189 } 190 else if (object == null || getClass() != object.getClass()) 191 { 192 return false; 193 } 194 195 final ClassPathContext other = (ClassPathContext) object; 196 197 return ObjectUtils.equals(archiveRoot, other.archiveRoot); 198 } 199 200 @Override 201 public String toString() 202 { 203 return archiveRoot != null ? archiveRoot : "<unspecified archive root>"; 204 } 205 }