/*******************************************************************************
* Copyright (c) 2009 MATERNA Information & Communications. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html. For further
* project-related information visit http://www.ws4d.org. The most recent
* version of the JMEDS framework can be obtained from
* http://sourceforge.net/projects/ws4d-javame.
******************************************************************************/
package org.ws4d.java.wsdl;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import org.ws4d.java.DPWSFramework;
import org.ws4d.java.communication.monitor.ResourceLoader;
import org.ws4d.java.io.fs.FileSystem;
import org.ws4d.java.schema.Schema;
import org.ws4d.java.schema.SchemaException;
import org.ws4d.java.structures.EmptyStructures;
import org.ws4d.java.structures.HashMap;
import org.ws4d.java.structures.HashMap.Entry;
import org.ws4d.java.structures.HashSet;
import org.ws4d.java.structures.Iterator;
import org.ws4d.java.structures.Set;
import org.ws4d.java.types.QName;
import org.ws4d.java.types.URI;
import org.ws4d.java.util.Log;
import org.xmlpull.v1.XmlPullParserException;
/**
* This class implements the WSDL Manager for handling predefined WSDLs in a so
* called WSDL Repository.
*/
public class WSDLRepository {
// TODO: Remove this after OSAMi Demonstation!
public static final boolean DEMO_MODE = false;
private static final String DEMO_WSDL_COMMON = "OSAmICommonSensorService.wsdl";
private static final String DEMO_WSDL_PULSE = "OSAmIPulseService.wsdl";
private static final String DEMO_WSDL_O2 = "OSAmISpO2Service.wsdl";
// TODO extract as framework(?) property
private static final String REPO_PATH = "wsdl_repo";
private static final String INDEX_FILE = "index.idx";
private static final int READ_BUFFER_SIZE = 1024;
private static final WSDLRepository INSTANCE = new WSDLRepository();
private final FileSystem fs;
/*
* for WSDL files: key = port type as QName, value = WSDL file name within
* repository as String
*/
/*
* for XML Schema files: key = schema location as String (as found within
* include/import statement), value = XML Schema file name within repository
* as String
*/
private final HashMap index = new HashMap();
public static String getRepoPath() {
return REPO_PATH;
}
public static WSDLRepository getInstance() {
return INSTANCE;
}
public static WSDL loadWsdl(URI wsdlUri) throws IOException {
try {
return WSDL.parse(wsdlUri, true);
} catch (IOException e) {
Log.error("Unable to obtain WSDL from " + wsdlUri + ": " + e.getMessage());
throw e;
} catch (XmlPullParserException e) {
Log.error("Ill formatted WSDL from " + wsdlUri + ": " + e.getMessage());
throw new IOException(e.getMessage());
}
}
private WSDLRepository() {
super();
FileSystem fs = null;
try {
fs = DPWSFramework.getLocalFileSystem();
} catch (IOException e) {
/*
* no file system available within current runtime or framework not
* started
*/
Log.error("No local file system available, WSDL repository will not work.");
}
this.fs = fs;
if (fs != null) {
// initStore();
try {
loadIndex();
} catch (IOException e) {
if (Log.isDebug()) {
Log.debug("Unable to load WSDL Repository index file: " + e.getMessage());
}
}
}
}
public InputStream getWsdlInputStream(QName portType) {
if (fs == null) {
return null;
}
String wsdlFilePath;
synchronized (index) {
wsdlFilePath = (String) index.get(portType);
}
if (wsdlFilePath == null) {
return null;
}
try {
return fs.readFile(wsdlFilePath);
} catch (IOException e) {
Log.error("Unable to read WSDL file " + wsdlFilePath + ": " + e.getMessage());
}
return null;
}
public WSDL getWsdl(QName portType) {
try {
InputStream in = getWsdlInputStream(portType);
if (in == null) return null;
WSDL wsdl = WSDL.parse(in, true);
if (DEMO_MODE) {
String wsdlFilePath;
synchronized (index) {
Iterator it = index.keySet().iterator();
while (it.hasNext()) {
QName pt = (QName) it.next();
if (Log.isDebug()) {
Log.debug("PORTTYPE: " + pt, Log.DEBUG_LAYER_FRAMEWORK);
}
}
wsdlFilePath = (String) index.get(portType);
}
String fileName = wsdlFilePath.substring(REPO_PATH.length() + fs.fileSeparator().length());
if (Log.isDebug()) {
Log.debug("OSAMi Demomode: LOAD " + fileName, Log.DEBUG_LAYER_FRAMEWORK);
}
if (fileName != null && fileName.equals(DEMO_WSDL_COMMON)) {
/*
* get pulse WSDL
*/
WSDL pulse = getWSDL(DEMO_WSDL_PULSE);
if (pulse != null) {
pulse.addLinkedWsdl(wsdl);
}
} else if (fileName != null && fileName.equals(DEMO_WSDL_O2)) {
/*
* get O2 WSDL
*/
WSDL common = getWSDL(DEMO_WSDL_COMMON);
if (common != null) {
wsdl.addLinkedWsdl(common);
}
} else if (fileName != null && fileName.equals(DEMO_WSDL_PULSE)) {
/*
* get sensor WSDL
*/
WSDL common = getWSDL(DEMO_WSDL_COMMON);
if (common != null) {
wsdl.addLinkedWsdl(common);
}
}
}
in.close();
if (Log.isDebug()) {
Log.debug("WSDL: " + wsdl.toString(), Log.DEBUG_LAYER_FRAMEWORK);
}
return wsdl;
} catch (XmlPullParserException e) {
synchronized (index) {
Log.error("Ill formatted WSDL file " + index.get(portType) + ": " + e.getMessage());
}
} catch (IOException e) {
synchronized (index) {
Log.error("Unable to read WSDL file " + index.get(portType) + ": " + e.getMessage());
}
}
return null;
}
public Schema getSchema(String schemaLocation, String namespace) {
String filePath;
synchronized (index) {
String key = namespace == null ? schemaLocation : schemaLocation + '|' + namespace;
filePath = (String) index.get(key);
if (filePath == null) {
if (Log.isDebug()) {
Log.debug("Unable to find XML Schema for schema location " + schemaLocation + " and namespace " + namespace + " within WSDL Repository");
}
return null;
}
}
try {
InputStream in = fs.readFile(filePath);
if (in == null) {
Log.warn("Unable to read XML Schema file " + filePath);
return null;
}
try {
return Schema.parse(in, null, true);
} finally {
in.close();
}
} catch (IOException e) {
Log.error("Unable to read XML Schema file " + filePath + ": " + e.getMessage());
} catch (XmlPullParserException e) {
Log.error("Ill formatted XML Schema file " + filePath + ": " + e.getMessage());
} catch (SchemaException e) {
Log.error("Invalid XML Schema file " + filePath + ": " + e.getMessage());
}
return null;
}
public Iterator getPortTypes() {
synchronized (index) {
if (index.isEmpty()) {
return EmptyStructures.EMPTY_ITERATOR;
}
Set portTypes = new HashSet();
for (Iterator it = index.keySet().iterator(); it.hasNext();) {
Object o = it.next();
if (o instanceof QName) {
// this index entry is for a WSDL port type
portTypes.add(o);
}
// else it is an index entry for an XML Schema file
}
return portTypes.iterator();
}
}
public WSDL loadAndStore(URI fromUri, String fileName) throws IOException {
store(fromUri, fileName);
if (fileName == null) {
fileName = fromUri.toString();
} else if ("".equals(fileName)) {
return loadWsdl(fromUri);
}
// load from repository directory
return getWSDL(fileName);
}
public WSDL loadAndStore(InputStream in, String fileName) throws IOException {
WSDL wsdl = null;
try {
wsdl = WSDL.parse(in, true);
in.close();
if (wsdl != null) {
// TODO make file name unique
store(wsdl, fileName);
}
} catch (XmlPullParserException e) {
Log.error("Ill formatted WSDL file: " + e.getMessage());
}
return wsdl;
}
public WSDL loadAndStore(URI wsdlUri) throws IOException {
return loadAndStore(wsdlUri, wsdlUri.toString());
}
public void store(WSDL wsdl, String fileName) {
if (DEMO_MODE) {
Log.debug("OSAMi Demomode: STORE " + fileName, Log.DEBUG_LAYER_FRAMEWORK);
if (fileName != null && fileName.equals(DEMO_WSDL_COMMON)) {
/*
* get pulse WSDL
*/
WSDL pulse = getWSDL(DEMO_WSDL_PULSE);
if (pulse != null) {
pulse.addLinkedWsdl(wsdl);
}
WSDL o2 = getWSDL(DEMO_WSDL_O2);
if (o2 != null) {
o2.addLinkedWsdl(wsdl);
}
} else if (fileName != null && fileName.equals(DEMO_WSDL_O2)) {
/*
* get O2 WSDL
*/
WSDL common = getWSDL(DEMO_WSDL_COMMON);
if (common != null) {
wsdl.addLinkedWsdl(common);
}
} else if (fileName != null && fileName.equals(DEMO_WSDL_PULSE)) {
/*
* get sensor WSDL
*/
WSDL common = getWSDL(DEMO_WSDL_COMMON);
if (common != null) {
wsdl.addLinkedWsdl(common);
}
}
}
String filePath = REPO_PATH + fs.fileSeparator() + fs.escapeFileName(fileName);
try {
OutputStream out = fs.writeFile(filePath);
wsdl.serialize(out);
out.close();
index(wsdl, filePath);
flushIndex();
} catch (IOException e) {
Log.error("Unable to write to WSDL file " + filePath + ": " + e.getMessage());
}
}
/**
* Imports a WSDL including any referenced WSDL and XML Schema files from
* the specified location <code>fromLocation</code>. If
* <code>fileName</code> is neither <code>null</code> nor equal to the empty
* String <code>""</code>, the WSDL will be stored within the
* repository to a file with that name. Otherwise, if it is
* <code>null</code>, a file name will be derived from the URI the WSDL is
* loaded from (<code>fromLocation</code>). Finally, if
* <code>fileName</code> is equal to the empty String, the WSDL file will be
* searched for its target namespace and a file name will be derived there
* from.
*
* @param fromLocation the location to load the file from
* @param fileName the name of the file to store the imported WSDL to within
* the repository; may be <code>null</code> or the empty String
* @throws IOException if either accessing the WSDL or any of the files it
* references or writing into the repository fails
*/
public void store(URI fromLocation, String fileName) throws IOException {
store(fromLocation, fileName, true);
}
private void store(URI fromLocation, String fileName, boolean flushIndex) throws IOException {
if (Log.isDebug()) {
Log.debug("Importing WSDL from " + fromLocation);
}
WSDL wsdl = null;
if (fileName == null) {
fileName = fromLocation.toString();
} else if ("".equals(fileName)) {
try {
wsdl = WSDL.parse(fromLocation, false);
} catch (XmlPullParserException e) {
throw new IOException(e.getMessage());
}
fileName = wsdl.getTargetNamespace();
if (!fileName.endsWith("/")) {
fileName += '/';
}
fileName += "description.wsdl";
}
String outputPath = REPO_PATH + fs.fileSeparator() + fs.escapeFileName(fileName);
if (fs.fileExists(outputPath)) {
if (Log.isDebug()) {
Log.debug("WSDL Repository resource already exists: " + outputPath);
}
return;
}
ResourceLoader rl = DPWSFramework.getResourceAsStream(fromLocation);
InputStream in = rl.getInputStream();
if (in == null) {
throw new IOException("Unable to read from " + fromLocation);
}
OutputStream out = fs.writeFile(outputPath);
byte[] buffer = new byte[READ_BUFFER_SIZE];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
out.flush();
out.close();
in.close();
if (wsdl == null) {
try {
wsdl = WSDL.parse(fromLocation, false);
} catch (XmlPullParserException e) {
throw new IOException(e.getMessage());
}
}
index(wsdl, outputPath);
storeReferencedFiles(fromLocation, fileName, flushIndex, wsdl);
}
/**
* @param fromLocation
* @param fileName
* @param flushIndex
* @param wsdl
* @throws IOException
*/
private void storeReferencedFiles(URI fromLocation, String fileName, boolean flushIndex, WSDL wsdl) throws IOException {
URI fileNameUri = new URI(fileName);
for (Iterator it = wsdl.getImports().values().iterator(); it.hasNext();) {
String importLocation = (String) it.next();
URI newUri = URI.absolutize(fromLocation, importLocation);
store(newUri, URI.absolutize(fileNameUri, importLocation).toString(), false);
}
for (Iterator it = wsdl.getTypes(); it.hasNext();) {
Schema schema = (Schema) it.next();
for (Iterator it2 = schema.getIncludes().iterator(); it2.hasNext();) {
String schemaLocation = (String) it2.next();
URI newUri = URI.absolutize(fromLocation, schemaLocation);
storeSchema(newUri, URI.absolutize(fileNameUri, schemaLocation).toString(), schemaLocation, false);
}
for (Iterator it2 = schema.getImports().values().iterator(); it2.hasNext();) {
String schemaLocation = (String) it2.next();
URI newUri = URI.absolutize(fromLocation, schemaLocation);
storeSchema(newUri, URI.absolutize(fileNameUri, schemaLocation).toString(), schemaLocation, false);
}
}
if (flushIndex) {
flushIndex();
}
}
/**
* Imports an XML Schema including any referenced XML Schema files from the
* specified location <code>fromLocation</code>. If <code>fileName</code> is
* neither <code>null</code> nor equal to the empty String
* <code>""</code>, the schema will be stored within the
* repository to a file with that name. Otherwise, if it is
* <code>null</code>, a file name will be derived from the URI the schema is
* loaded from (<code>fromLocation</code>). Finally, if
* <code>fileName</code> is equal to the empty String, the schema file will
* be searched for its target namespace and a file name will be derived
* there from.
*
* @param fromLocation the location to load the file from
* @param fileName the name of the file to store the imported schema to
* within the repository; may be <code>null</code> or the empty
* String
* @throws IOException if either accessing the schema or any of the files it
* references or writing into the repository fails
*/
public void storeSchema(URI fromLocation, String fileName) throws IOException {
storeSchema(fromLocation, fileName, null, true);
}
private void storeSchema(URI fromLocation, String fileName, String schemaLocation, boolean flushIndex) throws IOException {
if (Log.isDebug()) {
Log.debug("Importing XML Schema from " + fromLocation);
}
Schema schema = null;
if (fileName == null) {
fileName = fromLocation.toString();
} else if ("".equals(fileName)) {
try {
schema = Schema.parse(fromLocation, false);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
fileName = schema.getTargetNamespace();
}
String outputPath = REPO_PATH + fs.fileSeparator() + fs.escapeFileName(fileName);
if (fs.fileExists(outputPath)) {
if (Log.isDebug()) {
Log.debug("WSDL Repository resource already exists: " + outputPath);
}
return;
}
ResourceLoader rl = DPWSFramework.getResourceAsStream(fromLocation);
InputStream in = rl.getInputStream();
if (in == null) {
throw new IOException("Unable to read from " + fromLocation);
}
OutputStream out = fs.writeFile(outputPath);
byte[] buffer = new byte[READ_BUFFER_SIZE];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
out.flush();
out.close();
in.close();
if (schema == null) {
try {
schema = Schema.parse(fromLocation, false);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
if (schemaLocation == null) {
schemaLocation = fileName;
}
synchronized (index) {
String ns = schema.getTargetNamespace();
if (ns != null) {
index.put(schemaLocation + '|' + ns, outputPath);
} else {
index.put(schemaLocation, outputPath);
}
}
URI fileNameUri = new URI(fileName);
for (Iterator it2 = schema.getIncludes().iterator(); it2.hasNext();) {
String childSchemaLocation = (String) it2.next();
URI newUri = URI.absolutize(fromLocation, childSchemaLocation);
storeSchema(newUri, URI.absolutize(fileNameUri, childSchemaLocation).toString(), childSchemaLocation, false);
}
for (Iterator it = schema.getImports().values().iterator(); it.hasNext();) {
String importLocation = (String) it.next();
URI newUri = URI.absolutize(fromLocation, importLocation);
storeSchema(newUri, URI.absolutize(fileNameUri, importLocation).toString(), importLocation, false);
}
if (flushIndex) {
flushIndex();
}
}
public WSDL getWSDL(String fileName) {
String filePath = REPO_PATH + fs.fileSeparator() + fs.escapeFileName(fileName);
try {
InputStream in = fs.readFile(filePath);
try {
WSDL wsdl = WSDL.parse(in, true);
return wsdl;
} catch (IOException e) {
Log.error("Unable to read WSDL file " + filePath + ": " + e.getMessage());
} catch (XmlPullParserException e) {
Log.error("Ill formatted WSDL file " + filePath + ": " + e.getMessage());
} finally {
in.close();
}
} catch (IOException e) {
if (Log.isDebug()) {
Log.debug("WSDL file not found within WSDL Repository: " + filePath);
}
}
return null;
}
public void delete(QName portType) {
synchronized (index) {
String filePath = (String) index.get(portType);
if (filePath != null) {
fs.deleteFile(filePath);
index.remove(portType);
try {
flushIndex();
} catch (IOException e) {
Log.warn("Unable to write WSDL Repository index file: " + e.getMessage());
}
}
}
}
/**
* Removes the entire content of the WSDL repository.
*/
public void clear() {
synchronized (index) {
for (Iterator it = index.values().iterator(); it.hasNext();) {
String filePath = (String) it.next();
fs.deleteFile(filePath);
}
fs.deleteFile(REPO_PATH + fs.fileSeparator() + INDEX_FILE);
index.clear();
}
}
// /**
// *
// */
// public void updateStore() {
// String[] knownWsdlFiles = fs.listFiles(REPO_PATH);
// if (knownWsdlFiles == null) {
// index.clear();
// return;
// }
// for (int i = 0; i < knownWsdlFiles.length; i++) {
// String wsdlFile = knownWsdlFiles[i];
// String filePath = REPO_PATH + fs.fileSeparator() + wsdlFile;
//
// // add
// if (!index.containsKey(filePath)) {
// try {
// InputStream in = fs.readFile(filePath);
// try {
// WSDL wsdl = WSDL.parse(in, false);
// in.close();
// index(wsdl, filePath);
// } catch (XmlPullParserException e) {
// Log.error("Ill formatted WSDL file " + filePath + ": " + e.getMessage());
// }
// } catch (IOException e) {
// Log.error("Unable to read WSDL file " + filePath + ": " +
// e.getMessage());
// }
// }
// }
// ArrayList l = new ArrayList();
// // remove
// Iterator itPortType = index.keySet().iterator();
// while (itPortType.hasNext()) {
// QName portType = (QName) itPortType.next();
// int i;
// for (i = 0; i < knownWsdlFiles.length; i++) {
// if ((REPO_PATH + fs.fileSeparator() +
// knownWsdlFiles[i]).equals(index.get(portType))) break;
// }
// if (i == knownWsdlFiles.length) l.add(portType);
// }
// for (Iterator it = l.iterator(); it.hasNext();)
// index.remove(it.next());
// }
/**
* @param wsdl
* @param filePath
*/
private void index(WSDL wsdl, String filePath) {
synchronized (index) {
for (Iterator it = wsdl.getPortTypes(); it.hasNext();) {
WSDLPortType portType = (WSDLPortType) it.next();
index.put(portType.getName(), filePath);
}
}
}
// private void initStore() {
// String[] knownWsdlFiles = fs.listFiles(REPO_PATH);
// if (knownWsdlFiles == null) {
// return;
// }
// for (int i = 0; i < knownWsdlFiles.length; i++) {
// String wsdlFile = knownWsdlFiles[i];
// String filePath = REPO_PATH + fs.fileSeparator() + wsdlFile;
// try {
// InputStream in = fs.readFile(filePath);
// try {
// WSDL wsdl = WSDL.parse(in, false);
// in.close();
// index(wsdl, filePath);
// } catch (XmlPullParserException e) {
// Log.error("Ill formatted WSDL file " + filePath + ": " + e.getMessage());
// }
// } catch (IOException e) {
// Log.error("Unable to read WSDL file " + filePath + ": " +
// e.getMessage());
// }
// }
// }
private void loadIndex() throws IOException {
synchronized (index) {
InputStream in = fs.readFile(REPO_PATH + fs.fileSeparator() + INDEX_FILE);
if (in == null) {
if (Log.isDebug()) {
Log.debug("No WSDL Repository index file available.");
}
return;
}
try {
Reader reader = new InputStreamReader(in);
int c;
StringBuffer buffer = new StringBuffer(64);
while ((c = reader.read()) != -1) {
int recordCode;
switch (c) {
case 'w': // WSDL record, expect QName as key in James
// Clark's
// notation
case 's': // XML Schema record, expect String as key
recordCode = c;
break;
case '\n': // empty line
continue;
default: // unexpected record code, consume entire line
while ((c = reader.read()) != -1 && c != '\n')
;
continue;
}
if (buffer == null) {
buffer = new StringBuffer(64);
} else if (buffer.length() > 0) {
buffer.delete(0, buffer.length());
}
// read the key into buffer
while ((c = reader.read()) != -1 && c != '=' && c != '\n') {
buffer.append((char) c);
}
switch (c) {
case -1:
Log.warn("Unexpected end of stream while reading WSDL Repository index file.");
return;
case '\n':
Log.warn("Unexpected end of line while reading WSDL Repository index file. Buffer contents: " + buffer);
continue;
default: // equality sign, start reading value next
}
String key = buffer.toString();
if (buffer.length() > 0) {
buffer.delete(0, buffer.length());
}
while ((c = reader.read()) != -1 && c != '\n') {
buffer.append((char) c);
}
switch (recordCode) {
case 'w':
int idx = key.indexOf('}');
String ns = null;
if (idx != -1) {
ns = key.substring(key.charAt(0) == '{' ? 1 : 0, idx);
key = key.substring(idx + 1);
}
QName portType = new QName(key, ns);
index.put(portType, buffer.toString());
break;
case 's':
index.put(key, buffer.toString());
break;
}
}
} finally {
in.close();
}
}
}
private void flushIndex() throws IOException {
synchronized (index) {
if (index.isEmpty()) {
return;
}
OutputStream fout = fs.writeFile(REPO_PATH + fs.fileSeparator() + INDEX_FILE);
try {
Writer writer = new OutputStreamWriter(fout);
for (Iterator it = index.entrySet().iterator(); it.hasNext();) {
Entry ent = (Entry) it.next();
Object key = ent.getKey();
if (key instanceof QName) {
// WSDL file
writer.write('w');
} else {
// string, i.e. XML Schema
writer.write('s');
}
writer.write(key.toString());
writer.write('=');
writer.write(ent.getValue().toString());
writer.write('\n');
}
writer.flush();
writer.close();
fout.flush();
if (Log.isDebug()) {
Log.debug("Flushing WSDL Repository index file done.");
}
} finally {
fout.close();
}
}
}
}