package org.opennaas.core.resources.shell;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.felix.gogo.commands.Argument;
import org.apache.felix.gogo.commands.Command;
import org.apache.felix.gogo.commands.Option;
import org.opennaas.core.resources.IResource;
import org.opennaas.core.resources.IResourceManager;
import org.opennaas.core.resources.ResourceException;
import org.opennaas.core.resources.descriptor.Information;
import org.opennaas.core.resources.descriptor.ResourceDescriptor;
import org.opennaas.core.resources.descriptor.network.NetworkTopology;
import org.xml.sax.SAXException;
/**
* Create a new resource from the URL or file given on the karaf shell
*
* @author Scott Campbell (CRC)
*
*/
@Command(scope = "resource", name = "create", description = "Create one or more resources from a given descriptor")
public class CreateResourceCommand extends GenericKarafCommand {
private final String NAME_SCHEMA = "/descriptor.xsd";
@Argument(index = 0, name = "paths or urls", description = "A space delimited list of file paths or urls to resource descriptors ", required = true, multiValued = true)
private List<String> paths;
@Option(name = "--profile", aliases = { "-p" }, description = "Allows explicit declaration of profile to be used")
String profileName;
@Override
protected Object doExecute() throws Exception {
printInitCommand("create resource");
IResourceManager manager = getResourceManager();
List<ResourceDescriptor> descriptors = getDescriptors(paths);
int counter = 0;
for (ResourceDescriptor descriptor : descriptors) {
try {
totalFiles++;
createResource(manager, descriptor);
counter++;
// printSymbol(underLine);
} catch (NullPointerException f) {
printError("Error creating Resource "
+ descriptor.getInformation().getType() + ":"
+ descriptor.getInformation().getName());
printError(f);
}
}
if (counter == 0) {
printInfo("No resource has been created.");
} else {
printInfo("Created " + counter + " resource/s of " + totalFiles);
}
printEndCommand();
return null;
}
public int createResource(IResourceManager manager,
ResourceDescriptor descriptor) {
// check if profile option is active
if (profileName != null && profileName != "") {
// Override profile in the descriptor
descriptor.setProfileId(profileName);
}
try {
// printInfo("Creating Resource ...... ");
IResource resource = manager.createResource(descriptor);
Information information = resource.getResourceDescriptor()
.getInformation();
printInfo("Created resource " + information.getType() + ":"
+ information.getName());
return 0;
} catch (ResourceException e) {
printError(e.getLocalizedMessage());
if (manager.getResourceTypes().isEmpty()) {
printError("There aren't any Resource Repositories registered.");
}
return -1;
} catch (NullPointerException e) {
printError(e);
return -1;
}
}
public ResourceDescriptor getResourceDescriptor(String filename)
throws JAXBException, IOException, ResourceException, SAXException {
InputStream stream = null;
// First try a URL
try {
URL url = new URL(filename);
log.info("URL: " + url);
stream = url.openStream();
} catch (MalformedURLException ignore) {
// Then try a file
log.info("file: " + filename);
stream = new FileInputStream(filename);
}
ResourceDescriptor resourceDescriptor = getDescriptor(stream);
if (resourceDescriptor.getInformation().getType() == null
|| resourceDescriptor.getInformation().getType() == "") {
throw new ResourceException(
"Invalid ResourceDescriptor: Must specify a resource type.");
}
if (resourceDescriptor.getInformation().getName().equals("")
|| resourceDescriptor.getInformation().getName() == null) {
throw new ResourceException(
"Invalid ResourceDescriptor: Must specify a resource name.");
}
/* try to load network topology */
String networkTopologyFilePath = resourceDescriptor.getFileTopology();
if (networkTopologyFilePath != null
&& !networkTopologyFilePath.trim().equals("")) {
/* checks */
// TODO Improve to get descriptors from relative paths
if (!networkTopologyFilePath.startsWith("/")) {
log.info(networkTopologyFilePath + " doesnt start with /");
throw new ResourceException(
"The network file decriptor has to be absolute path");
}
try {
printInfo("Loading network file descriptor: "
+ networkTopologyFilePath);
NetworkTopology networkTopology = getNetworkDescriptor(networkTopologyFilePath);
resourceDescriptor.setNetworkTopology(networkTopology);
} catch (FileNotFoundException e) {
throw new FileNotFoundException("Could not found file "
+ networkTopologyFilePath);
}
}
printInfo("Descriptor loaded for resource "
+ resourceDescriptor.getInformation().getType() + ":"
+ resourceDescriptor.getInformation().getName());
return resourceDescriptor;
}
public ResourceDescriptor getDescriptor(InputStream stream)
throws JAXBException, SAXException {
ResourceDescriptor descriptor = null;
try {
JAXBContext context = JAXBContext
.newInstance(ResourceDescriptor.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
/* check wellformat xml with xsd */
// TODO I CAN NOT UNDERSTAND WHY WE CAN GET THE LOADER FROM A
// COMMAND
// SchemaFactory sf = SchemaFactory.newInstance(
// javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
// ClassLoader loader =
// Thread.currentThread().getContextClassLoader();
// Schema schema = sf.newSchema(new
// StreamSource(loader.getResourceAsStream(NAME_SCHEMA)));
// unmarshaller.setSchema(schema);
descriptor = (ResourceDescriptor) unmarshaller.unmarshal(stream);
} finally {
try {
stream.close();
} catch (IOException e) {
// Ingore
}
}
return descriptor;
}
// public IResourceManager getResourceManager() throws Exception {
// IResourceManager resourceManager = Activator.getResourceManagerService();
//
// return resourceManager;
// }
private List<ResourceDescriptor> getDescriptors(List<String> paths) {
List<URL> urls = new ArrayList<URL>();
List<ResourceDescriptor> descriptors = new ArrayList<ResourceDescriptor>();
for (String path : paths) {
urls.addAll(getDescriptorURLs(path));
}
for (URL url : urls) {
try {
descriptors.add(getResourceDescriptor(url.toString()));
} catch (FileNotFoundException f) {
printError("File not found: " + url.toString() + f.getMessage());
} catch (NullPointerException f) {
printError("Error parsing descriptor on " + url.toString());
} catch (JAXBException f) {
printError("Error parsing descriptor ");
printError(f);
} catch (ResourceException f) {
printError("In file: " + url.toString());
printError(f);
} catch (IOException e) {
printError("Error reading descriptor: " + url.toString(), e);
} catch (SAXException f) {
printError("Given file is not a valid descriptor. Check it complies with descriptor schema. Invalid file: "
+ url.toString());
printError(f);
}
}
return descriptors;
}
private List<URL> getDescriptorURLs(String path) {
List<URL> urls = new ArrayList<URL>();
try {
URL url = fileNameToUrl(path);
if (url.getProtocol().equals("file")) {
File file = new File(url.toURI());
if (file.isDirectory()) {
for (File fileInDirectory : file.listFiles()) {
if (fileInDirectory.getName().endsWith(".descriptor")) {
try {
urls.add(fileInDirectory.toURI().toURL());
} catch (MalformedURLException e) {
printError("Could not read file. Malformed path: "
+ fileInDirectory.toURI().toString());
}
}
}
} else {
if (file.getName().endsWith(".descriptor")) {
urls.add(url);
} else {
printError("The file type is not a valid for "
+ file.getName());
}
}
} else {
urls.add(url);
}
} catch (MalformedURLException e1) {
printError("Could not read file. Malformed path: " + path);
} catch (URISyntaxException e) {
printError("Could not read file. Malformed path: " + path);
}
return urls;
}
private URL fileNameToUrl(String pathOrUrl) throws MalformedURLException {
String url;
if (!pathOrUrl.contains("://")) {
url = "file:///" + pathOrUrl;
} else {
url = pathOrUrl;
}
return new URL(url);
}
/* methods to read descriptors */
/**
* Helper methods to test these functionality...
*
* @param filename
* @return
* @throws JAXBException
* @throws IOException
* @throws ResourceException
* @throws SAXException
*/
private NetworkTopology getNetworkDescriptor(String filename)
throws JAXBException, IOException, ResourceException, SAXException {
InputStream stream = null;
// First try a URL
try {
URL url = new URL(filename);
log.info("URL: " + url);
stream = url.openStream();
} catch (MalformedURLException ignore) {
// Then try a file
// Added class loader to read files
// TODO check to read topologies with relative paths
// stream =
// this.getClass().getClassLoader().getResourceAsStream(filename);
log.error("file: " + filename);
stream = new FileInputStream(filename);
}
NetworkTopology rd = loadNetworkDescriptor(stream);
return rd;
}
private NetworkTopology loadNetworkDescriptor(InputStream stream)
throws JAXBException, SAXException {
NetworkTopology descriptor = null;
try {
JAXBContext context = JAXBContext
.newInstance(NetworkTopology.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
/* check wellformat xml with xsd */
// TODO I CAN NOT UNDERSTAND WHY WE CAN GET THE LOADER FROM A
// COMMAND
// SchemaFactory sf = SchemaFactory.newInstance(
// javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
// ClassLoader loader =
// Thread.currentThread().getContextClassLoader();
// Schema schema = sf.newSchema(new
// StreamSource(loader.getResourceAsStream(NAME_SCHEMA)));
// unmarshaller.setSchema(schema);
descriptor = (NetworkTopology) unmarshaller.unmarshal(stream);
} finally {
try {
stream.close();
} catch (IOException e) {
// Ignore
}
}
return descriptor;
}
}