Project

General

Profile

Bug #5403 » EcogridWriter.java

Daniel Crawl, 06/15/2012 04:52 PM

 
1
/*
2
 * Copyright (c) 2003-2010 The Regents of the University of California.
3
 * All rights reserved.
4
 *
5
 * '$Author: tao $'
6
 * '$Date: 2011-04-06 18:22:21 -0700 (Wed, 06 Apr 2011) $' 
7
 * '$Revision: 27446 $'
8
 * 
9
 * Permission is hereby granted, without written agreement and without
10
 * license or royalty fees, to use, copy, modify, and distribute this
11
 * software and its documentation for any purpose, provided that the above
12
 * copyright notice and the following two paragraphs appear in all copies
13
 * of this software.
14
 *
15
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
16
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
18
 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
19
 * SUCH DAMAGE.
20
 *
21
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
22
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
24
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
25
 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
26
 * ENHANCEMENTS, OR MODIFICATIONS.
27
 *
28
 */
29

    
30
package org.ecoinformatics.seek.ecogrid;
31

    
32
import java.io.StringReader;
33
import java.io.StringWriter;
34
import java.util.UUID;
35

    
36
import javax.xml.parsers.DocumentBuilder;
37
import javax.xml.parsers.DocumentBuilderFactory;
38
import javax.xml.parsers.ParserConfigurationException;
39

    
40
import org.apache.commons.logging.Log;
41
import org.apache.commons.logging.LogFactory;
42
import org.apache.xml.serialize.XMLSerializer;
43
import org.apache.xpath.XPathAPI;
44
import org.ecoinformatics.ecogrid.EcogridObjType;
45
import org.ecoinformatics.ecogrid.client.AuthenticationServiceClient;
46
import org.ecoinformatics.ecogrid.client.PutServiceClient;
47
import org.ecoinformatics.seek.datasource.eml.eml2.Eml200Parser;
48
import org.w3c.dom.Document;
49
import org.w3c.dom.Node;
50
import org.w3c.dom.NodeList;
51
import org.xml.sax.InputSource;
52

    
53
import ptolemy.actor.TypedAtomicActor;
54
import ptolemy.actor.TypedIOPort;
55
import ptolemy.data.ObjectToken;
56
import ptolemy.data.StringToken;
57
import ptolemy.data.expr.Parameter;
58
import ptolemy.data.expr.StringParameter;
59
import ptolemy.data.type.BaseType;
60
import ptolemy.kernel.CompositeEntity;
61
import ptolemy.kernel.util.Attribute;
62
import ptolemy.kernel.util.IllegalActionException;
63
import ptolemy.kernel.util.NameDuplicationException;
64
import util.StaticUtil;
65

    
66
/**
67
 * This actor will write a data with metadata document into Ecogrid service.
68
 * 
69
 * @author tao
70
 */
71
public class EcogridWriter extends TypedAtomicActor {
72
	// /////////////////////////////////////////////////////////////////
73
	// // ports and parameters ////
74

    
75
	/*
76
	 * The input port, which is a multiport.
77
	 */
78
	// public TypedIOPort trigger;
79
	/* Source file to be uploaded */
80

    
81
	/**
82
	 * Input port. This should be a file path value of a local data file which
83
	 * will be upload to Ecogrid service
84
	 */
85
	public TypedIOPort sourceFileNamePort = null;
86
	
87
	public TypedIOPort sourceDataPort;
88
	
89
	/**
90
	 * Input port. This should a be string which is metadata describing the data
91
	 * file. This string will be uploaded to Ecogrid service as metadata.
92
	 */
93
	public TypedIOPort metadataPort = null;
94
	/**
95
	 * Output port. This will be the metadata docid which generated by the actor
96
	 * for future reference
97
	 */
98
	public TypedIOPort metadataDocidPort = null;
99
	/**
100
	 * Output port. This will be the data docid which generated by the actor for
101
	 * future reference
102
	 */
103
	public TypedIOPort dataDocidPort = null;
104

    
105
	private String metadataDocid = null;
106
	private String dataDocid = null;
107
	private String metadataUserName = null;
108
	private String metadataPasswd = null;
109
	private String metadataDestination = null;
110
	// private String dataUserName = null;
111
	// private String dataPasswd = null;
112
	// private String dataDestination = null;
113
	private String authenURL = null;
114
	private String localDataFileName = null;
115
	private byte[] localData;
116
	private String metadataContent = null;
117

    
118
	protected final static Log log;
119
	protected final static boolean isDebugging;
120
	static {
121
		log = LogFactory
122
				.getLog("org.ecoinformatics.seek.ecogrid.EcoGridServicesController");
123
		isDebugging = log.isDebugEnabled();
124
	}
125

    
126
	private String docIdSuffix = "doc";
127

    
128
	private static final String DATAFILENAMEPORT = "dataFileNamePort";
129
	private static final String DATAPORT = "dataPort";
130
	private static final String METADATAPORT = "metadata";
131
	private static final String METADATADOCIDPORT = "metadataDocid";
132
	private static final String DATADOCIDPORT = "dataDocid";
133
	private static final String METADATADESTINATION = "metadataDestination";
134
	private static final String DISTRIBUTIONPATH = "physical/distribution/online/url";
135
	private static final String SEPERATOR = ".";
136
	private static final String ECOGRIDPROTOCOL = "ecogrid://knb/";
137
	private static final String DEFAULTECOGRIDPUTSERVER = "http://ecogrid.ecoinformatics.org/knb/services/PutService";
138
	private static final String DEFAULTECOGRIDAUTHENSERVER = "http://ecogrid.ecoinformatics.org/knb/services/AuthenticationService";
139
	private static final String AUTHENURL = "authenticationURL";
140
	private static final String USERNAME = "userName";
141
	private static final String PASSWORD = "passWord";
142

    
143
	/**
144
	 * Ecogrid service URL for receiving metadata and data
145
	 */
146
	public StringParameter metadataDesParam = null;
147
	/**
148
	 * Ecogrid service URL for authenticating user
149
	 */
150
	public StringParameter authenURLParam = null;
151
	/**
152
	 * User name for authenticatication. For example, it is a DN for knb ldap
153
	 * server. uid=smith,o=NCEAS,dc=eocinformatics,dc=org
154
	 */
155
	public StringParameter usernameParam = null;
156
	/**
157
	 * Password for this user
158
	 */
159
	public StringParameter passwordParam = null;
160

    
161
	// public FileParameter localDataFileNameParameter = null;
162

    
163
	public EcogridWriter(CompositeEntity container, String name)
164
			throws IllegalActionException, NameDuplicationException {
165
		super(container, name);
166
		// input ports
167
		metadataPort = new TypedIOPort(this, METADATAPORT, true, false);
168
		metadataPort.setMultiport(false);
169
		metadataPort.setTypeEquals(BaseType.STRING);
170
		sourceFileNamePort = new TypedIOPort(this, DATAFILENAMEPORT, true,
171
				false);
172
		sourceFileNamePort.setMultiport(false);
173
		sourceFileNamePort.setTypeEquals(BaseType.STRING);
174
		
175
		sourceDataPort = new TypedIOPort(this, DATAPORT, true, false);
176
	    sourceDataPort.setTypeEquals(BaseType.OBJECT);
177

    
178
		// output ports
179
		metadataDocidPort = new TypedIOPort(this, METADATADOCIDPORT, false,
180
				true);
181
		metadataDocidPort.setMultiport(false);
182
		metadataDocidPort.setTypeEquals(BaseType.STRING);
183
		dataDocidPort = new TypedIOPort(this, DATADOCIDPORT, false, true);
184
		dataDocidPort.setMultiport(false);
185
		dataDocidPort.setTypeEquals(BaseType.STRING);
186

    
187
		// parameters
188
		metadataDesParam = new StringParameter(this, METADATADESTINATION);
189
		metadataDesParam.setExpression(DEFAULTECOGRIDPUTSERVER);
190
		authenURLParam = new StringParameter(this, AUTHENURL);
191
		authenURLParam.setExpression(DEFAULTECOGRIDAUTHENSERVER);
192
		usernameParam = new StringParameter(this, USERNAME);
193
		passwordParam = new StringParameter(this, PASSWORD);
194

    
195
		// localDataFileNameParameter = new FileParameter(this,
196
		// LOCATDATFILENAME);
197
		_attachText("_iconDescription", "<svg>\n"
198
				+ "<rect x=\"-25\" y=\"-20\" " + "width=\"50\" height=\"40\" "
199
				+ "style=\"fill:white\"/>\n"
200
				+ "<polygon points=\"-15,-10 -12,-10 -8,-14 -1,-14 3,-10"
201
				+ " 15,-10 15,10, -15,10\" " + "style=\"fill:red\"/>\n"
202
				+ "</svg>\n");
203
	}
204

    
205
	// /////////////////////////////////////////////////////////////////
206
	// // public methods ////
207

    
208
	/**
209
	 * If the specified attribute is <i>fileOrURL </i> and there is an open file
210
	 * being read, then close that file and open the new one; if the attribute
211
	 * is <i>numberOfLinesToSkip </i> and its value is negative, then throw an
212
	 * exception. In the case of <i>fileOrURL </i>, do nothing if the file name
213
	 * is the same as the previous value of this attribute.
214
	 * 
215
	 * @param attribute
216
	 *            The attribute that has changed.
217
	 * @exception IllegalActionException
218
	 *                If the specified attribute is <i>fileOrURL </i> and the
219
	 *                file cannot be opened, or the previously opened file
220
	 *                cannot be closed; or if the attribute is
221
	 *                <i>numberOfLinesToSkip </i> and its value is negative.
222
	 */
223

    
224
	/**
225
	 * Determine the attribute changed value
226
	 * 
227
	 * @param attribute
228
	 *            The attribute that changed.
229
	 * @exception IllegalActionException
230
	 *                If the output type is not recognized.
231
	 */
232
	public void attributeChanged(Attribute attribute)
233
			throws IllegalActionException {
234
		if (attribute == metadataDesParam) {
235
			metadataDestination = getValueForAttributeChange(metadataDesParam);
236
		} else if (attribute == authenURLParam) {
237
			authenURL = getValueForAttributeChange(authenURLParam);
238
			;
239
		} else if (attribute == usernameParam) {
240
			metadataUserName = getValueForAttributeChange(usernameParam);
241
		} else if (attribute == passwordParam) {
242
			metadataPasswd = getValueForAttributeChange(passwordParam);
243
		}
244
	}
245

    
246
	/*
247
	 * Get new value for attribute changes
248
	 */
249
	private String getValueForAttributeChange(Parameter attribute) 
250
	                                      throws IllegalActionException{
251
	  String newValue = null;
252
	  if(attribute != null ) {
253
	    StringToken token = (StringToken)attribute.getToken();
254
	    if(token != null) {
255
	      newValue = token.stringValue();
256
	    }
257
	  }
258
		if (isDebugging) {
259
			log.debug("The value of attribute is " + newValue);
260
		}
261
		//System.out.println("======the value of attribute is "+newValue);
262
		return newValue;
263
	}
264

    
265
	/**
266
	 * @return Description of the Returned Value
267
	 * @exception IllegalActionException
268
	 *                Description of Exception
269
	 * @since
270
	 */
271
	public boolean prefire() throws IllegalActionException {
272
		int revision = 1;
273
		
274
		if(sourceDataPort.numberOfSources() > 0) {
275
		    ObjectToken object = (ObjectToken) sourceDataPort.get(0);
276
		    localData = (byte[]) object.getValue();
277
		}	
278
		else if (sourceFileNamePort.numberOfSources() > 0) {
279
	        // get data file name
280
			if (!sourceFileNamePort.hasToken(0))
281
				return false;
282
			StringToken sourcefnToken = (StringToken) sourceFileNamePort.get(0);
283
			localDataFileName = sourcefnToken.stringValue();
284
			// localDataFileNameParameter.setExpression(localDataFileName);
285
			if (isDebugging) {
286
				log.debug("The localDataFileName is " + localDataFileName);
287
			}
288
		}
289
		/*
290
		 * else { localDataFileName =
291
		 * localDataFileNameParameter.asFile().getPath(); }
292
		 */
293

    
294
		dataDocid = generateDocId(docIdSuffix, revision);
295
		// get metadata
296
		if (metadataPort.getWidth() > 0) {
297

    
298
			if (!metadataPort.hasToken(0))
299
				return false;
300
			StringToken metadataToken = (StringToken) metadataPort.get(0);
301
			metadataContent = metadataToken.stringValue();
302
			if (isDebugging) {
303
				log.debug("The original metadata is " + metadataContent);
304
			}
305
			// replace the url part
306
			String newURL = ECOGRIDPROTOCOL + dataDocid;
307
			metadataDocid = generateDocId(docIdSuffix, revision);
308
			try {
309
				metadataContent = replaceDistributionURLAndPackageID(metadataContent,
310
						newURL, metadataDocid);
311
			} catch (Exception e) {
312
				throw new IllegalActionException(e.getMessage());
313
			}
314

    
315
		}
316
		
317
		return super.prefire();
318
	}
319

    
320
	/**
321
	 * Output the data lines into an array.
322
	 * 
323
	 * @exception IllegalActionException
324
	 *                If there's no director.
325
	 */
326

    
327
	public void fire() throws IllegalActionException {
328
		super.fire();
329
		try {
330
		  long start = System.currentTimeMillis();
331
			// load metadata and data to ecogrid
332
			String sessionId = loginEcoGrid(authenURL, metadataUserName,
333
					metadataPasswd);
334
			uploadDataFile(metadataDestination, localDataFileName, dataDocid, sessionId);
335
			uploadMetadata(metadataDestination, metadataContent, metadataDocid,
336
					sessionId);
337
			long end = System.currentTimeMillis();
338
			System.out.println("**********EcogridWriter uploading data and metadata took "+(end-start)+" ms.");
339
			// output metadata docid and data docid
340
			TypedIOPort pp = (TypedIOPort) this.getPort(METADATADOCIDPORT);
341
			pp.send(0, new StringToken(metadataDocid));
342
			TypedIOPort pp1 = (TypedIOPort) this.getPort(DATADOCIDPORT);
343
			pp1.send(0, new StringToken(dataDocid));
344
			metadataDocid = null;
345
			dataDocid = null;
346
		} catch (Exception e) {
347
			throw new IllegalActionException(e.getMessage());
348
		}
349

    
350
	}
351

    
352
	/*
353
	 * This method will operate login action and return a session id
354
	 */
355
	private String loginEcoGrid(String authernURL, String userName,
356
			String password) throws Exception {
357
		String sessionId = null;
358
		AuthenticationServiceClient client = new AuthenticationServiceClient(
359
				authernURL);
360
		sessionId = client.login_action(userName, password);
361
		if (isDebugging) {
362
			log.debug("The session id is " + sessionId);
363
		}
364
		// client.destory();
365
		return sessionId;
366
	}
367

    
368
	/*
369
	 * Method to upload data
370
	 */
371
	private void uploadDataFile(String destURL, String localFileName,
372
			String docid, String sessionId) throws Exception {
373
		int type = EcogridObjType.DATA;
374
		// client.createEcoGridPutLevelOnePortType();
375
		byte[] data;
376
		
377
		if(localData != null)
378
		{
379
		    data = localData;
380
		}
381
		else
382
		{
383
		    data = StaticUtil.getBytesArrayFromFile(localFileName);
384
		}
385
        if(data.length < 10)
386
        {
387
            System.out.println("WARNING: read " + data.length + " bytes in data file");
388
        }
389

    
390
        boolean error = true;
391
        int tries = 5;
392
        while(tries > 0 && error)
393
        {
394
            tries--;
395
            error = false;
396
            PutServiceClient client = new PutServiceClient(destURL);
397
		    try 
398
            { 
399
                client.put(data, docid, type, sessionId); 
400
            }
401
            catch(Exception e) 
402
            { 
403
                System.out.println("data exception: " + e.getMessage());
404
                if(tries > 0)
405
                {
406
                    error = true;
407
                }
408
                else
409
                {
410
                    throw e;
411
                }
412
            }
413
        }
414
		// client.destroy();
415
	}
416

    
417
	/*
418
	 * Method to upload metadata
419
	 */
420
	private void uploadMetadata(String destURL, String metadataContent,
421
			String docid, String sessionId) throws Exception {
422
		int type = EcogridObjType.METADATA;
423
		byte[] content = metadataContent.getBytes();
424
        if(content.length < 10)
425
        {
426
            System.out.println("WARNING: read " + content.length + " bytes in metadata file");
427
        }
428
		PutServiceClient client = new PutServiceClient(destURL);
429
		// client.createEcoGridPutLevelOnePortType();
430
		try { client.put(content, docid, type, sessionId); }
431
        catch(Exception e) { 
432
            System.out.println("metadata exception: " + e.getMessage());
433
            throw e;
434
        }
435
		// client.destroy();
436
	}
437

    
438
	/*
439
	 * After genarte docid for data file, the original metadata need to replace
440
	 * the distribution url by new value. Currently we just consider eml as
441
	 * metadata
442
	 */
443
	private String replaceDistributionURLAndPackageID(String originalMetadata, String newURL, String newMetadataID)
444
			throws Exception {
445
		String newMetadata = null;
446
		if (originalMetadata != null) {
447
			DocumentBuilder parser = null;
448
			try {
449
				DocumentBuilderFactory factory = DocumentBuilderFactory
450
						.newInstance();
451
				// factory.setNamespaceAware(true);
452
				parser = factory.newDocumentBuilder();
453
				if (parser == null) {
454
					throw new Exception("Could not create Document parser in "
455
							+ "EcogridWriter");
456
				}
457
			} catch (ParserConfigurationException pce) {
458
				throw new Exception("Could not create Document parser in "
459
						+ "EcogridWriter: " + pce.getMessage());
460
			}
461
			log.debug("after generate dom parser");
462
			Document doc = null;
463
			StringReader reader = new StringReader(originalMetadata);
464
			InputSource in = new InputSource(reader);
465
			log.debug("after generate inputsource");
466
			doc = parser.parse(in);
467
			log.debug("after parsing inputsource");
468
			// we assuming the metadata only have one entity
469
			String tablePath = Eml200Parser.TABLEENTITY + "/"
470
					+ DISTRIBUTIONPATH;
471
			NodeList tableNodeList = XPathAPI.selectNodeList(doc, tablePath);
472
			String rasterPath = Eml200Parser.SPATIALRASTERENTITY + "/"
473
					+ DISTRIBUTIONPATH;
474
			NodeList rasterNodeList = XPathAPI.selectNodeList(doc, rasterPath);
475
			String vectorPath = Eml200Parser.SPATIALVECTORENTITY + "/"
476
					+ DISTRIBUTIONPATH;
477
			NodeList vectorNodeList = XPathAPI.selectNodeList(doc, vectorPath);
478
			String procedurePath = Eml200Parser.STOREDPROCEDUREENTITY + "/"
479
					+ DISTRIBUTIONPATH;
480
			NodeList procedureNodeList = XPathAPI.selectNodeList(doc,
481
					procedurePath);
482
			String viewPath = Eml200Parser.VIEWENTITY + "/" + DISTRIBUTIONPATH;
483
			NodeList viewNodeList = XPathAPI.selectNodeList(doc, viewPath);
484
			String otherEntityPath = Eml200Parser.OTHERENTITY + "/"
485
					+ DISTRIBUTIONPATH;
486
			NodeList otherEntityNodeList = XPathAPI.selectNodeList(doc,
487
					otherEntityPath);
488
			if (tableNodeList != null && tableNodeList.getLength() != 0) {
489
				// have tableEntity
490
				log.debug("in data table path for replacement");
491
				setNewValueForNode(tableNodeList, newURL);
492
			} else if (rasterNodeList != null
493
					&& rasterNodeList.getLength() != 0) {
494
				setNewValueForNode(rasterNodeList, newURL);
495
			} else if (vectorNodeList != null
496
					&& vectorNodeList.getLength() != 0) {
497
				setNewValueForNode(vectorNodeList, newURL);
498
			} else if (procedureNodeList != null
499
					&& procedureNodeList.getLength() != 0) {
500
				setNewValueForNode(procedureNodeList, newURL);
501
			} else if (viewNodeList != null && viewNodeList.getLength() != 0) {
502
				setNewValueForNode(viewNodeList, newURL);
503
			} else if (otherEntityNodeList != null
504
					&& otherEntityNodeList.getLength() != 0) {
505
				setNewValueForNode(otherEntityNodeList, newURL);
506
			}
507
			
508
			//replace package id
509
			String packagePath= "/*[local-name() = '"+Eml200Parser.EML+"']/@"+Eml200Parser.PACKAGEID;
510
			NodeList packageIDNodeList = XPathAPI.selectNodeList(doc, packagePath);
511
			setNewValueForAttribute(packageIDNodeList, newMetadataID);
512
			// serialize the DOM tree
513
			StringWriter writer = new StringWriter();
514
			XMLSerializer serializer = new XMLSerializer();
515
			serializer.setOutputCharStream(writer);
516
			// serializer.setOutputByteStream(System.out);
517
			serializer.serialize(doc);
518
			newMetadata = writer.toString();
519
			// writer.write(newMetadata);
520
			log.debug("The new metadata with new data reference is \n"
521
					+ newMetadata);
522

    
523
		}
524
		return newMetadata;
525
	}
526

    
527
	/*
528
	 * Docid will look like suffix.id.rev. suffix and rev will be passed as a
529
	 * parameter, but id will generate in this method. In order to make sure the
530
	 * id is unique, it will generated by Date object.
531
	 */
532
	private String generateDocId(String suffix, int rev) {
533
	  //double random = Math.random();
534
	  //int randomInt = (new Double(random*100)).intValue();
535
		String docid = null;
536
		//Date currentTime = new Date();
537
		//String id = Long.toString(currentTime.getTime());
538
		//id= id+randomInt;
539
	    String id = UUID.randomUUID().toString();
540
		docid = suffix + SEPERATOR + id + SEPERATOR + rev;
541
		log.debug("The generated docid is " + docid);
542
		return docid;
543
	}
544

    
545
	/*
546
	 * This method will set up new value for the list. We only replace the first
547
	 * one
548
	 */
549
	private void setNewValueForNode(NodeList list, String newValue) {
550
		Node cn = list.item(0).getFirstChild();
551
		if ((cn != null) && (cn.getNodeType() == Node.TEXT_NODE)) {
552
			log.debug("set new value " + newValue + " for distribution url");
553
			cn.setNodeValue(newValue);
554
		}	
555
	}
556
	
557
	/*
558
	 * Set a new value for an attribute node.
559
	 */
560
	private void setNewValueForAttribute(NodeList list, String newValue){
561
	  if(list != null && list.getLength() >0){
562
	    Node cn = list.item(0);
563
	    if(cn != null && cn.getNodeType() == Node.ATTRIBUTE_NODE){
564
	      //System.out.println("Set new value "+newValue +" for attribute"+cn.getNodeName());
565
	      cn.setNodeValue(newValue);
566
	    }
567
	  }
568
	}
569
	
570
	
571

    
572
}
(1-1/3)