001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.dataproxy.metadata.ADN; 031 032import java.io.IOException; 033import java.net.MalformedURLException; 034import java.net.URL; 035import java.util.Collections; 036import java.util.HashMap; 037import java.util.Hashtable; 038import java.util.Map; 039import java.util.Vector; 040 041import org.apache.commons.logging.Log; 042import org.apache.commons.logging.LogFactory; 043import org.ecoinformatics.ecogrid.queryservice.query.QueryType; 044import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetType; 045import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeRecord; 046import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeRecordReturnField; 047import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadata; 048import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadataRecordStructure; 049import org.ecoinformatics.ecogrid.queryservice.resultset.ResultsetTypeResultsetMetadataRecordStructureReturnField; 050import org.ecoinformatics.seek.ecogrid.MetadataSpecificationInterface; 051import org.ecoinformatics.seek.ecogrid.exception.EcoGridException; 052import org.ecoinformatics.seek.ecogrid.exception.InvalidEcogridQueryException; 053import org.ecoinformatics.seek.ecogrid.quicksearch.SearchQueryGenerator; 054import org.ecoinformatics.seek.ecogrid.quicksearch.SortableResultRecord; 055import org.ecoinformatics.seek.ecogrid.quicksearch.SortableResultRecordComparator; 056import org.kepler.configuration.ConfigurationManager; 057import org.kepler.configuration.ConfigurationProperty; 058import org.kepler.dataproxy.datasource.geon.GEONDatabaseResource; 059import org.kepler.dataproxy.datasource.geon.GEONShpResource; 060import org.xml.sax.SAXException; 061 062import ptolemy.actor.TypedAtomicActor; 063import ptolemy.kernel.CompositeEntity; 064import ptolemy.kernel.util.IllegalActionException; 065import ptolemy.kernel.util.NameDuplicationException; 066 067/** 068 * This class is a plugin for adn namespace to transfer query group to ecogrid 069 * query type. It also provide a method to create quick search query 070 * 071 * @author Efrat Jaeger-Frank 072 */ 073 074public class ADNMetadataSpecification extends MetadataSpecificationInterface { 075 public static final String ADNNAMESPACE = "http://www.sdsc.geongrid.org/services/search"; 076 private static final int NAMESPACEARRAYLENGTH = 1; 077 private static final String OPERATOR = "LIKE"; 078 private static final String FILERFIELD = "filerField"; 079 private static final String UNKNOWNTITLE = "unknownTitle"; 080 private static final String REPLACE = "#value#"; 081 private static final String QUERYID = "geon-quick-search-query"; 082 private static final int GAP = 106; 083 084 private int _numResults = 0; 085 protected String namespace = null; 086 protected String queryId = null; 087 088 private static final String DOCURL = "//documentation[namespace=\"" 089 + ADNNAMESPACE + "\"]/url"; 090 private static final String DOCUSERNAME = "//documentation[namespace=\"" 091 + ADNNAMESPACE + "\"]/username"; 092 private Map fieldIdtoNameMap = new HashMap(); 093 094 // private String recordTitle = null; 095 // private Vector entityName = null; 096 097 protected final static Log log; 098 static { 099 log = LogFactory 100 .getLog("org.kepler.dataproxy.metadata.ADN.ADNMetadataSpecification"); 101 } 102 103 /** 104 * Default constructor 105 */ 106 public ADNMetadataSpecification() { 107 namespace = ADNNAMESPACE; // TODO: REPLACE 108 queryId = QUERYID; 109 }// Eml200EcoGridQueryTransfer 110 111 /** 112 * Returns a URL to the ADN documentation 113 * 114 * @throws MalformedURLException 115 */ 116 117 public static URL getDocumentation(String recordId) 118 throws MalformedURLException { 119 120 ConfigurationManager confMan = ConfigurationManager.getInstance(); 121 ConfigurationProperty documentationProperty = confMan.getProperty( 122 ConfigurationManager.getModule("common")); 123 String docURL = documentationProperty.getProperty("documentation.url").getValue(); 124 String userName = documentationProperty.getProperty("documentation.username").getValue(); 125 126 docURL += "?id=" + recordId + "&username=" + userName + "#in_browser"; 127 return new URL(docURL); 128 } 129 130 /** 131 * Method to create a quick query search 132 * 133 * @param value 134 * String 135 * @return QueryType 136 */ 137 public QueryType getQuickSearchEcoGridQuery(String value) 138 throws InvalidEcogridQueryException { 139 Hashtable replaceMapping = new Hashtable(); 140 replaceMapping.put(REPLACE, value); 141 SearchQueryGenerator eml200QueryGenerator = new SearchQueryGenerator( 142 queryId, replaceMapping); 143 QueryType ecogridQuery = eml200QueryGenerator.getQuery(); 144 return ecogridQuery; 145 146 }// getQuickSearchEcoGridQuery 147 148 /** 149 * Method to create a ecogrid query 150 * 151 * @return QueryType 152 */ 153 public QueryType getEcoGridQuery() { 154 QueryType ecogridQuery = null; 155 return ecogridQuery; 156 }// getEcoGridQuery 157 158 /** 159 * This method will transfer ResultsetType java object to array of 160 * ResultRecord java object. The ResultRecord object can be shown in kepler. 161 * If the results is null or there is no record in the result, null will be 162 * return 163 * 164 * @param ResultsetType 165 * results the result need to be transform 166 * @param String 167 * endpoints the search end point 168 * @return ResultRecord[] the resultrecord need be returned. 169 */ 170 public boolean transformResultset(ResultsetType results, String endpoint, 171 CompositeEntity container, Vector aResultList) throws SAXException, 172 IOException, EcoGridException, NameDuplicationException, 173 IllegalActionException { 174 if (results == null) { 175 return false; // ??? 176 } 177 178 ResultsetTypeResultsetMetadata metaData = results 179 .getResultsetMetadata(); 180 if (metaData != null) { 181 populateFieldMap(metaData); 182 } 183 184 // transfer ResultType to a vector of sorted titles containing 185 // (title,ids,returnFieldsVector) 186 Vector resultsetItemList = transformResultsetType(results); 187 188 // transfer the sored vector (contains eml2resultsetitem object to an 189 // array 190 // of ResultRecord 191 int numResults = resultsetItemList.size(); 192 193 aResultList = new Vector(); 194 195 Hashtable titleList = new Hashtable();// This hashtable is for keeping 196 // track 197 // if there is a duplicate title 198 for (int i = 0; i < numResults; i++) { 199 try { 200 SortableResultRecord source = (SortableResultRecord) resultsetItemList 201 .elementAt(i); 202 String title = source.getTitle(); 203 log.debug("The title is " + title); 204 String id = source.getId(); 205 log.debug("The id is " + id); 206 Vector returnFieldList = source.getEntityList(); 207 // if couldn't find id, skip this record 208 if (id == null || id.trim().equals("")) { 209 continue; 210 } 211 212 // if couldn't find title, assign a one to it -- <j> 213 if (title == null || title.trim().equals("")) { 214 title = "<" + i + ">"; 215 } 216 if (titleList.containsKey(title)) { 217 title = title + " " + i; 218 } 219 titleList.put(title, title); 220 221 String format = null; 222 String description = ""; 223 224 for (int j = 0; j < returnFieldList.size(); j++) { 225 ResultsetTypeRecordReturnField returnField = (ResultsetTypeRecordReturnField) returnFieldList 226 .elementAt(j); 227 if (returnField == null) { 228 continue; 229 } 230 String returnFieldId = returnField.getId(); 231 String returnFieldValue = returnField.get_value(); 232 String returnFieldName = (String) fieldIdtoNameMap 233 .get(returnFieldId); 234 if (returnFieldName != null 235 && !returnFieldName.trim().equals("")) { 236 if (returnFieldName.equals("description")) { 237 log.debug("The description after parsing is " 238 + returnFieldValue); 239 description = returnFieldValue; 240 } else if (returnFieldName.equals("format")) { 241 format = returnFieldValue; 242 } 243 } 244 } 245 246 TypedAtomicActor newRecord = null; 247 if (format.trim().toLowerCase().indexOf("database") > -1) { // VERIFY!!!! 248 log.debug("The entiy is a database resource"); 249 newRecord = new GEONDatabaseResource(container, title); 250 ((GEONDatabaseResource) newRecord)._idAtt.setExpression(id); 251 ((GEONDatabaseResource) newRecord)._endpointAtt 252 .setExpression(endpoint); 253 ((GEONDatabaseResource) newRecord)._namespaceAtt 254 .setExpression(namespace); 255 ((GEONDatabaseResource) newRecord)._descriptionAtt 256 .setExpression(restyleDescription(description)); 257 } else if (format.equals("shapefile")) { 258 log.debug("The entiy is a shapefile resource"); 259 newRecord = new GEONShpResource(container, title); 260 ((GEONShpResource) newRecord)._idAtt.setExpression(id); 261 ((GEONShpResource) newRecord)._endpointAtt 262 .setExpression(endpoint); 263 ((GEONShpResource) newRecord)._namespaceAtt 264 .setExpression(namespace); 265 ((GEONShpResource) newRecord)._descriptionAtt 266 .setExpression(restyleDescription(description)); 267 268 } else 269 continue; 270 271 aResultList.add(newRecord); 272 273 } catch (Exception e) { 274 continue; 275 } 276 }// for 277 278 _numResults = aResultList.size(); 279 return _numResults > 0; 280 } 281 282 /* 283 * Method to transform array of AnyRecordType to array of EML2ResultsetItem 284 */ 285 private Vector transformResultsetType(ResultsetType result) { 286 Vector itemList = new Vector(); 287 if (result == null) { 288 return itemList; 289 } 290 ResultsetTypeRecord[] records = result.getRecord(); 291 if (records == null) { 292 return itemList; 293 } 294 295 int numRecords = records.length; 296 // transfer every records from source to a dest - EML2ResultsetItem obj 297 for (int i = 0; i < numRecords; i++) { 298 ResultsetTypeRecord currentRecord = records[i]; 299 if (currentRecord == null) { 300 continue; 301 } 302 String docid = currentRecord.getIdentifier(); 303 log.debug("The doc id after parsing resultset is " + docid); 304 // if couldn't find identifier, we don't need it 305 if (docid == null || docid.trim().equals("")) { 306 continue; 307 } 308 ResultsetTypeRecordReturnField[] recordReturnFieldList = currentRecord 309 .getReturnField(); 310 if (recordReturnFieldList == null) { 311 continue; 312 } 313 314 String recordTitle = null; 315 316 Vector returnFieldList = new Vector(); 317 318 int length = recordReturnFieldList.length; 319 for (int j = 0; j < length; j++) { 320 ResultsetTypeRecordReturnField currentReturnField = recordReturnFieldList[j]; 321 if (currentReturnField == null) { 322 continue; 323 } 324 String returnFieldId = currentReturnField.getId(); 325 String returnFieldValue = currentReturnField.get_value(); 326 String returnFieldName = (String) fieldIdtoNameMap 327 .get(returnFieldId); 328 if (returnFieldName != null 329 && !returnFieldName.trim().equals("")) { 330 if (returnFieldName.equals("title")) { 331 log.debug("The title after parsing is " 332 + returnFieldValue); 333 recordTitle = returnFieldValue; 334 recordTitle = replaceDotByDash(recordTitle); 335 } else { 336 returnFieldList.add(currentReturnField); // the other 337 // field 338 // will be 339 // used 340 // later. 341 } 342 } 343 344 }// for 345 if (recordTitle == null) { 346 recordTitle = UNKNOWNTITLE + i; 347 } 348 SortableResultRecord newItem = new SortableResultRecord( 349 recordTitle, docid, returnFieldList); 350 itemList.add(newItem); 351 352 }// for 353 Collections.sort(itemList, new SortableResultRecordComparator()); 354 return itemList; 355 } 356 357 /** 358 * Initialize the mapping between return fields ids and names 359 * 360 * @param metaData 361 */ 362 private void populateFieldMap(ResultsetTypeResultsetMetadata metaData) { 363 ResultsetTypeResultsetMetadataRecordStructure recordStructure = metaData 364 .getRecordStructure(); 365 ResultsetTypeResultsetMetadataRecordStructureReturnField[] fields = recordStructure 366 .getReturnField(); 367 if (fields != null) { 368 for (int i = 0; i < fields.length; i++) { 369 String value = fields[i].getName(); 370 String id = fields[i].getId(); 371 fieldIdtoNameMap.put(id, value); 372 // fieldNametoIdHash.put( value, id ); 373 } 374 } 375 } 376 377 /** 378 * Add new lines to provider a nicer display of the description. 379 * 380 * @param detail 381 * the additional information about the record 382 */ 383 private String restyleDescription(String description) { 384 int fromInd = 0; 385 int prevSpaceInd = 0; 386 String newDescription = ""; 387 int descLen = description.length(); 388 while (fromInd + GAP < descLen) { 389 int nextSpaceInd = description.indexOf(' ', fromInd + GAP); 390 prevSpaceInd = description.lastIndexOf(' ', nextSpaceInd - 1); // make 391 // it 392 // backword. 393 newDescription += description.substring(fromInd, prevSpaceInd) 394 + "\n"; 395 fromInd = prevSpaceInd + 1; 396 } 397 newDescription += description.substring(fromInd); 398 return newDescription; 399 } 400 401 /** 402 * Creates GEONDataResource items (derived from Source) and adds them into 403 * the container 404 * 405 * @param aResults 406 * @param aEndPointURLStr 407 * @param aContainer 408 * @param aResultList 409 * @throws SAXException 410 * @throws IOException 411 * @throws EcoGridException 412 * @throws NameDuplicationException 413 * @throws IllegalActionException 414 */ 415 public boolean addResultsetRecordsToContainer(ResultsetType results, 416 String endpoint, CompositeEntity container, Vector aResultList) 417 throws SAXException, IOException, EcoGridException, 418 NameDuplicationException, IllegalActionException { 419 // parse the resultset into ResultRecord array and stored it into 420 // a vector 421 try { 422 return transformResultset(results, endpoint, container, aResultList); 423 } catch (Exception ee) { 424 log 425 .debug( 426 "The error to transform from resultset to GEONDataResource ", 427 ee); 428 } 429 return false; 430 } 431 432 /** 433 * 434 * @return Returns a unique name that descrobes this class, often it is the 435 * name of the class that implments the interface 436 */ 437 public String getName() { 438 return getClass().getName(); 439 } 440 441 /** 442 * 443 */ 444 public String getBriefName() { 445 return "Geology"; 446 } 447 448 /** 449 * 450 * @return returns the number of results that for this data. 451 */ 452 public int getNumResults() { 453 return _numResults; 454 } 455 456}// Eml200EcoGridQueryTransfer