/*
* Licensed 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.
*/
package org.apache.aries.subsystem.core.internal;
import static org.apache.aries.util.filesystem.IDirectoryFinder.IDIR_SCHEME;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import org.apache.aries.util.filesystem.FileSystem;
import org.apache.aries.util.filesystem.IDirectory;
import org.apache.aries.util.filesystem.IDirectoryFinder;
import org.osgi.framework.Version;
public class Location {
enum LocationType {
SUBSYSTEM("subsystem", "subsystem"), IDIRFINDER(IDIR_SCHEME, IDIR_SCHEME), URL("url", null), UNKNOWN("unknown", null);
final String toString;
final String scheme;
LocationType(String toString, String scheme) {this.toString = toString; this.scheme = scheme;}
@Override
public String toString() {return toString;}
};
private final LocationType type;
private final String value;
private final URI uri;
private final URL url;
private final SubsystemUri subsystemUri;
private final IllegalArgumentException subsystemUriException;
/*
* type, value, uri are always set to some non-null value, url and
* subsystemUri depend on the type.
*/
public Location(String location) throws MalformedURLException, URISyntaxException {
value = location;
URI locationUri = null;
try {
locationUri = new URI(location);
} catch ( URISyntaxException urise ) {
// ignore
}
if (locationUri == null) {
type = LocationType.UNKNOWN;
url = null;
uri = null;
subsystemUri = null;
subsystemUriException = null;
} else if (locationUri.isAbsolute()) { // i.e. looks like scheme:something
String scheme = locationUri.getScheme();
if (LocationType.SUBSYSTEM.scheme.equals(scheme)) {
type = LocationType.SUBSYSTEM;
SubsystemUri ssUri;
IllegalArgumentException ssUriException = null;
try {
ssUri = new SubsystemUri(location);
} catch (IllegalArgumentException ex) {
// In some cases the SubsystemUri can't be parsed by the SubsystemUri parser.
ssUri = null;
ssUriException = ex;
}
subsystemUri = ssUri;
subsystemUriException = ssUriException;
if (subsystemUri != null) {
url = subsystemUri.getURL(); // subsystem uris may contain a nested url.
uri = (url==null) ? null : url.toURI();
} else {
url = null;
uri = locationUri;
}
} else if (LocationType.IDIRFINDER.scheme.equals(scheme)) {
type = LocationType.IDIRFINDER;
subsystemUri = null;
subsystemUriException = null;
url = null;
uri = locationUri;
} else { // otherwise will only accept a url, (a url
type = LocationType.URL; // always has a scheme, so fine to have
subsystemUri = null; // this inside the 'if isAbsolute' block).
subsystemUriException = null;
URL localUrl = null;
try {
localUrl = locationUri.toURL();
} catch ( final MalformedURLException mue) {
// ignore
}
url = localUrl;
uri = locationUri;
}
} else {
type = LocationType.UNKNOWN;
url = null;
uri = null;
subsystemUri = null;
subsystemUriException = null;
}
}
public String getValue() {
return value;
}
public String getSymbolicName() {
if (subsystemUriException != null) {
throw subsystemUriException;
}
return (subsystemUri!=null) ? subsystemUri.getSymbolicName() : null;
}
public Version getVersion() {
if (subsystemUriException != null) {
throw subsystemUriException;
}
return (subsystemUri!=null) ? subsystemUri.getVersion() : null;
}
public IDirectory open() throws IOException, URISyntaxException {
switch (type) {
case IDIRFINDER :
return retrieveIDirectory();
case SUBSYSTEM : // drop through to share 'case url' code
case URL :
if ("file".equals(url.getProtocol()))
return FileSystem.getFSRoot(new File(uri));
else
return FileSystem.getFSRoot(url.openStream());
case UNKNOWN:
// Only try to create a URL with the location value here. If the
// location was just a string and an InputStream was provided, this
// method will never be called.
return FileSystem.getFSRoot(new URL(value).openStream());
default : // should never get here as switch should cover all types
throw new UnsupportedOperationException("cannot open location of type " + type);
}
}
/*
* Although the uri should contain information about the directory finder
* service to use to retrieve the directory, there are not expected to be
* many such services in use (typically one), so a simple list of all
* directory finders is maintained by the activator and we loop over them in
* turn until the desired directory is retrieved or there are no more finders
* left to call.
*/
private IDirectory retrieveIDirectory() throws IOException {
Collection<IDirectoryFinder> iDirectoryFinders = Activator.getInstance().getIDirectoryFinders();
for(IDirectoryFinder iDirectoryFinder : iDirectoryFinders) {
IDirectory directory = iDirectoryFinder.retrieveIDirectory(uri);
if (directory!=null)
return directory;
}
throw new IOException("cannot find IDirectory corresponding to id " + uri);
}
@Override
public String toString() {
return value;
}
}