001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.servicediscovery.description;
028:
029: import com.hp.hpl.jena.ontology.OntDocumentManager;
030: import com.hp.hpl.jena.ontology.OntModelSpec;
031: import com.hp.hpl.jena.ontology.OntModel;
032: import com.hp.hpl.jena.ontology.OntResource;
033: import com.hp.hpl.jena.rdf.model.Model;
034: import com.hp.hpl.jena.rdf.model.ModelFactory;
035: import com.hp.hpl.jena.rdf.model.RDFException;
036: import com.hp.hpl.jena.rdf.model.RDFNode;
037: import com.hp.hpl.jena.rdf.model.Resource;
038: import com.hp.hpl.jena.rdf.model.Statement;
039: import com.hp.hpl.jena.shared.JenaException;
040: import com.hp.hpl.jena.vocabulary.RDF;
041:
042: import org.cougaar.servicediscovery.Constants;
043: import org.cougaar.util.Configuration;
044: import org.cougaar.util.log.Logger;
045: import org.cougaar.util.log.Logging;
046:
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.io.File;
050: import java.net.URL;
051: import java.util.ArrayList;
052: import java.util.Collection;
053: import java.util.Iterator;
054:
055: /**
056: * Implements ProviderDescription
057: * Wraps the Jena parser object ( model) with convenience accessors
058: * At the ProviderDescription level, an OWL ServiceProvider is associated
059: * with a number of ServiceDescriptions (which correspond to OWL ServiceProfiles).
060: */
061:
062: public class ProviderDescriptionImpl implements ProviderDescription {
063:
064: //store the model that Jena parses from the file
065: protected OntModel model = null;
066: private String fileName;
067: private String cougaarInstallPath;
068:
069: private static Logger logger = Logging
070: .getLogger(ProviderDescription.class);
071:
072: private static Boolean LOCKED;
073:
074: static {
075: LOCKED = Boolean.FALSE;
076: }
077:
078: public static void main(String args[]) {
079:
080: ProviderDescriptionImpl pd = new ProviderDescriptionImpl();
081: boolean status = pd.parseOWL("1-AD.ARMY.MIL.profile.owl");
082:
083: logger.shout("main: Model class = " + pd.model.getClass());
084:
085: Resource serviceProfileResource = pd.model
086: .getResource(Profile.SERVICEPROFILE.getURI());
087:
088: logger.shout("main: serviceProfileResource = "
089: + serviceProfileResource);
090:
091: Collection serviceProfiles = pd.getServicePs();
092: for (Iterator iterator = serviceProfiles.iterator(); iterator
093: .hasNext();) {
094: Resource serviceProfile = (Resource) iterator.next();
095:
096: logger.shout("\n serviceProfileResource = "
097: + serviceProfile + " class = "
098: + serviceProfile.getClass() + " has uri = "
099: + serviceProfile.getURI());
100: for (Iterator propertiesIterator = serviceProfile
101: .listProperties(); propertiesIterator.hasNext();) {
102: logger.shout("\t property = "
103: + propertiesIterator.next());
104: }
105: }
106:
107: Statement serviceProvider = pd.getServiceProvider();
108: logger.shout("\n serviceProvider = " + serviceProvider
109: + " resource = " + serviceProvider.getResource()
110: + " resource class = "
111: + serviceProvider.getResource().getClass());
112: logger
113: .shout("\n serviceProviderName = "
114: + pd.getProviderName());
115:
116: serviceProfiles = pd.getServiceProfiles();
117: for (Iterator iterator = serviceProfiles.iterator(); iterator
118: .hasNext();) {
119: ServiceProfile serviceProfile = (ServiceProfile) iterator
120: .next();
121:
122: logger.shout("\n serviceProfile = " + serviceProfile);
123: }
124:
125: logger.shout("\n organizationType = "
126: + pd.getOrganizationType());
127:
128: logger.shout("\n ServiceProfile uri = "
129: + Profile.SERVICEPROFILE.getURI());
130: }
131:
132: /**
133: * This constructor builds an instance using a OWL file that is expected
134: * to contain at least one service profile and one service provider.
135: */
136: public ProviderDescriptionImpl() {
137: this .cougaarInstallPath = System.getProperty(
138: "org.cougaar.install.path", "");
139: }
140:
141: public boolean parseOWL(String owlFileName) {
142: return parseOWL(Constants.getServiceProfileURL(), owlFileName);
143: }
144:
145: public boolean parseOWL(URL serviceProfileURL, String owlFileName) {
146:
147: synchronized (LOCKED) {
148: if (logger.isDebugEnabled()) {
149: logger.debug("ProviderDescription.parseOWL for "
150: + owlFileName + " LOCKED == " + LOCKED);
151: }
152: if (LOCKED == Boolean.TRUE) {
153: return false;
154: } else {
155: LOCKED = Boolean.TRUE;
156: }
157: }
158:
159: if (logger.isDebugEnabled()) {
160: logger
161: .debug("ProviderDescription.parseOWL starting to parse "
162: + owlFileName);
163: }
164:
165: this .fileName = owlFileName;
166:
167: InputStream in = null;
168: try {
169: URL inURL = new URL(serviceProfileURL, owlFileName);
170: in = inURL.openStream();
171:
172: } catch (java.net.MalformedURLException mue) {
173: logger.error("Error: Cannot open file, " + fileName, mue);
174: } catch (IOException e1) {
175: logger.error("Error: Cannot open file, " + fileName, e1);
176: } finally {
177: if (in == null) {
178: LOCKED = Boolean.FALSE;
179: return false;
180: }
181: }
182:
183: model = ModelFactory.createOntologyModel();
184:
185: try {
186: model.enterCriticalSection(Model.WRITE);
187: OntDocumentManager mgr = model.getDocumentManager();
188:
189: String prefix = "file:";
190: if (cougaarInstallPath.length() > 0) {
191: prefix = prefix + cougaarInstallPath + File.separator;
192: }
193: prefix = prefix + "servicediscovery" + File.separator
194: + "data" + File.separator + "cached"
195: + File.separator;
196:
197: OntModelSpec s = new OntModelSpec(OntModelSpec.OWL_MEM);
198: s.setDocumentManager(mgr);
199:
200: mgr.addAltEntry("http://cougaar.owl", prefix
201: + "cougaar.owl");
202: mgr.addAltEntry(
203: "http://www.w3.org/1999/02/22-rdf-syntax-ns",
204: prefix + "rdfSyntaxNS.rdf");
205: mgr.addAltEntry("http://www.w3.org/2000/01/rdf-schema",
206: prefix + "rdfSchema.rdf");
207: mgr.addAltEntry("http://www.w3.org/2002/07/owl", prefix
208: + "owl.rdf");
209: mgr.addAltEntry("http://www.w3.org/2000/10/XMLSchema.xsd",
210: prefix + "XMLSchema.xsd");
211: mgr
212: .addAltEntry(
213: "http://www.daml.org/services/owl-s/1.0/Service.owl",
214: prefix + "Service.owl");
215: mgr
216: .addAltEntry(
217: "http://www.daml.org/services/owl-s/1.0/Process.owl",
218: prefix + "Process.owl");
219: mgr
220: .addAltEntry(
221: "http://www.daml.org/services/owl-s/1.0/Profile.owl",
222: prefix + "Profile.owl");
223: mgr
224: .addAltEntry(
225: "http://www.daml.org/services/owl-s/1.0/Grounding.owl",
226: prefix + "Grounding.owl");
227: mgr.addAltEntry(
228: "http://www.isi.edu/~pan/damltime/time-entry.owl",
229: prefix + "time-entry.owl");
230: mgr
231: .addAltEntry(
232: "http://www.isi.edu/~pan/damltime/timezone-ont.owl",
233: prefix + "timezone-ont.owl");
234:
235: try {
236: model.read(in, "");
237: } catch (RDFException e1) {
238: String helpMessage = "If the following StackTrace includes \"IO error while reading URL:\"\n"
239: + " you should examine the URL and confirm that it exists and\n"
240: + " is currently accessible. If the URL includes www.daml.org,\n"
241: + " this error means the daml site is temporarily unavailable.\n"
242: + " If the URL is a filepath or includes \"cougaar.owl\", this error\n"
243: + " probably means that your profile.owl files are inconsistent with\n"
244: + " your installation. One common way for this to happen is to have\n"
245: + " generated your profile.owl files from a perl script using an\n"
246: + " agent-input.txt file containing an incorrect or incorrectly formatted\n"
247: + " cougaarInstallPath. Alternatively, you may have generated your\n"
248: + " profile.owl files from a ruby script while your %COUGAAR_INSTALL_PATH%\n"
249: + " environment variable was not set correctly. Check these things and try\n"
250: + " regenerating your profile.owl files. \n";
251: logger.error(helpMessage + "Error parsing OWL file ["
252: + fileName + "]\n" + " Error Number: "
253: + e1.getErrorCode() + "\n"
254: + " Error Message: " + e1.getMessage() + "\n"
255: + " Error StackTrace: " + e1.getStackTrace()
256: + "\n" + " File: " + fileName, e1);
257: } catch (JenaException eJ) {
258: logger.error("JenaException in " + fileName + " "
259: + eJ.getMessage());
260: }
261:
262: if (logger.isDebugEnabled()) {
263: logger.debug("ProviderDescription.parseOWL for "
264: + owlFileName + " model == " + model);
265: Statement serviceProvider = getServiceProvider();
266: logger.debug("\n serviceProvider = " + serviceProvider
267: + " resource = "
268: + serviceProvider.getResource()
269: + " resource class = "
270: + serviceProvider.getResource().getClass());
271: logger.debug("\n serviceProviderName = "
272: + getProviderName());
273:
274: Collection serviceProfiles = getServiceProfiles();
275: for (Iterator iterator = serviceProfiles.iterator(); iterator
276: .hasNext();) {
277: ServiceProfile serviceProfile = (ServiceProfile) iterator
278: .next();
279:
280: logger.debug("\n serviceProfile = "
281: + serviceProfile);
282: }
283: logger.debug("\n organizationType = "
284: + getOrganizationType());
285: }
286: } finally {
287: model.leaveCriticalSection();
288: LOCKED = Boolean.FALSE;
289: }
290:
291: return true;
292: }
293:
294: public String getProviderName() {
295: String name = null;
296:
297: try {
298: Statement serviceProvider = this .getServiceProvider();
299: if (serviceProvider != null) {
300: name = serviceProvider
301: .getProperty(Profile.PROVIDERNAME).getString();
302: }
303: } catch (RDFException e) {
304: logger.error("Error getting Provider Name \n"
305: + " Error Number: " + e.getErrorCode() + "\n"
306: + " Error Message: " + e.getMessage() + "\n"
307: + " File: " + fileName, e);
308: }
309: return name;
310: }
311:
312: public Collection getBusinessCategories() {
313: ArrayList ret = new ArrayList();
314: String orgType = this .getOrganizationType();
315: if (!orgType.equals("None")) {
316: ret.add(new BusinessCategoryImpl("OrganizationTypes",
317: orgType, orgType));
318: }
319: return ret;
320: }
321:
322: public String getOrganizationType() {
323: String group = "None";
324: try {
325: Statement serviceProvider = this .getServiceProvider();
326: if (serviceProvider != null) {
327: Resource resource = serviceProvider.getResource();
328:
329: for (Iterator rdfTypeIterator = resource
330: .listProperties(RDF.type); rdfTypeIterator
331: .hasNext();) {
332: Statement statement = (Statement) rdfTypeIterator
333: .next();
334: Resource rdfResource = statement.getResource();
335: String localClassName = rdfResource.getLocalName();
336: int index = localClassName
337: .indexOf("ServiceProvider");
338: if (index > 0) {
339: return localClassName.substring(0, index);
340: }
341: }
342: }
343: } catch (RDFException e) {
344: logger.error("Error getOrganizationType failed \n"
345: + " Error Number: " + e.getErrorCode() + "\n"
346: + " Error Message: " + e.getMessage(), e);
347: }
348: return group;
349: }
350:
351: private Statement getServiceProvider() {
352: Statement serviceProvider = null;
353:
354: try {
355: Collection serviceProfiles = getServicePs();
356:
357: for (Iterator iterator = serviceProfiles.iterator(); iterator
358: .hasNext();) {
359: //This is a little strange. You can have multiple service profiles
360: //but each one should have an identical service provider. So, just
361: //read the information from the first service provider.
362: Resource serviceProfile = (Resource) iterator.next();
363:
364: if (logger.isDebugEnabled()) {
365: logger
366: .debug("getServiceProvider(): serviceProfile = "
367: + serviceProfile
368: + " Profile.PROVIDEDBY = "
369: + Profile.PROVIDEDBY);
370: }
371: //get the service provider
372: if (serviceProfile.hasProperty(Profile.PROVIDEDBY)) {
373: //should be only one
374: serviceProvider = serviceProfile
375: .getProperty(Profile.PROVIDEDBY);
376: break;
377: }
378: }
379: } catch (RDFException e) {
380: logger.error("Error getting Service Provider \n"
381: + " Error Number: " + e.getErrorCode() + "\n"
382: + " Error Message: " + e.getMessage() + "\n"
383: + " File: " + fileName, e);
384: }
385: return serviceProvider;
386: }
387:
388: private Collection getServicePs() {
389: ArrayList serviceProfiles = new ArrayList();
390:
391: try {
392: model.enterCriticalSection(Model.READ);
393: Resource serviceProfileResource = model
394: .getResource(Profile.SERVICEPROFILE.getURI());
395:
396: for (Iterator iterator = model.listObjects(); iterator
397: .hasNext();) {
398: RDFNode rdfNode = (RDFNode) iterator.next();
399: if (rdfNode instanceof Resource) {
400: Resource resource = (Resource) rdfNode;
401: if (resource.hasProperty(RDF.type,
402: serviceProfileResource)) {
403: serviceProfiles.add(resource);
404: }
405: }
406: }
407:
408: if (serviceProfiles.isEmpty() && logger.isInfoEnabled()) {
409: logger.info("Info: getServicePs() for [" + fileName
410: + "] is returning an empty collection.\n"
411: + "Model does not contain: "
412: + Profile.SERVICEPROFILE.getURI());
413: }
414: } finally {
415: model.leaveCriticalSection();
416: }
417:
418: return serviceProfiles;
419: }
420:
421: private Collection getServiceGroundings() {
422: ArrayList serviceGroundings = new ArrayList();
423:
424: try {
425: model.enterCriticalSection(Model.READ);
426: Resource groundingResource = model
427: .getResource(Profile.GROUNDING.getURI());
428:
429: for (Iterator iterator = model.listObjects(); iterator
430: .hasNext();) {
431: RDFNode rdfNode = (RDFNode) iterator.next();
432: if (rdfNode instanceof Resource) {
433: Resource resource = (Resource) rdfNode;
434: if (resource.hasProperty(RDF.type,
435: groundingResource)) {
436: serviceGroundings.add(resource);
437: }
438: }
439: }
440:
441: if (serviceGroundings.isEmpty() && logger.isInfoEnabled()) {
442: logger.info("Info: getServiceGroundings() for ["
443: + fileName
444: + "] is returning an empty collection.\n"
445: + "Model does not contain: "
446: + Profile.GROUNDING.getURI());
447: }
448: } finally {
449: model.leaveCriticalSection();
450: }
451:
452: return serviceGroundings;
453: }
454:
455: public Collection getServiceProfiles() {
456: Collection serviceProfiles = this .getServicePs();
457: Collection serviceGroundings = this .getServiceGroundings();
458:
459: //we need to match up the isProvidedBy and isSupportedBy so
460: //that we are pairing the correct grounding and profile.
461:
462: ArrayList serviceDescriptions = new ArrayList();
463:
464: Resource presentedbyResource = Profile.PRESENTEDBY;
465: for (Iterator iterator = serviceProfiles.iterator(); iterator
466: .hasNext();) {
467: Resource profile = (Resource) iterator.next();
468: Resource profileService = null;
469: //find the Service object
470: try {
471: profileService = profile.getProperty(
472: Profile.PRESENTEDBY).getResource();
473: } catch (RDFException e) {
474: logger.error("Error getting ServiceProfiles \n"
475: + " Error Number: " + e.getErrorCode() + "\n"
476: + " Error Message: " + e.getMessage() + "\n"
477: + " File: " + fileName, e);
478: }
479:
480: for (Iterator groundingIterator = serviceGroundings
481: .iterator(); groundingIterator.hasNext();) {
482: Resource grounding = (Resource) groundingIterator
483: .next();
484: Resource groundingService = null;
485: try {
486: groundingService = grounding.getProperty(
487: Profile.SUPPORTEDBY).getResource();
488:
489: if (groundingService.equals(profileService)) {
490: //if so, this profile/grounding pair makes a service profile object
491: serviceDescriptions.add(new ServiceProfileImpl(
492: profile, grounding));
493: }
494: } catch (RDFException e) {
495: logger.error(
496: "Error cannot find isSupportedBy in grounding \n"
497: + " Error Number: "
498: + e.getErrorCode() + "\n"
499: + " Error Message: "
500: + e.getMessage() + "\n"
501: + " File: " + fileName, e);
502: }
503: }
504: }
505: return serviceDescriptions;
506: }
507:
508: public String getProviderDescriptionURI() {
509: return "cougaar://" + getProviderName();
510: }
511:
512: public String toString() {
513: String ret = "ProviderDescription(name: "
514: + this .getProviderName();
515: ret = ret
516: .concat(" pd uri: " + this .getProviderDescriptionURI())
517: + " OrgType: " + this .getOrganizationType();
518: Iterator it = getServiceProfiles().iterator();
519: while (it.hasNext()) {
520: ret = ret.concat(" " + it.next().toString());
521: }
522: ret = ret.concat(")");
523: return ret;
524: }
525:
526: /**
527: * not implemented yet
528: */
529: public void writeOWLFiles(String outputFileBase) {
530: }
531:
532: }
|