/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package demo.soapclient; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.net.MalformedURLException; import java.rmi.RemoteException; import java.util.StringTokenizer; import java.util.HashMap; import javax.xml.rpc.ServiceException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import com.sun.org.apache.xml.internal.serialize.OutputFormat; import com.sun.org.apache.xml.internal.serialize.XMLSerializer; import fedora.client.FedoraClient; import fedora.common.Constants; import fedora.server.management.FedoraAPIM; import fedora.server.access.FedoraAPIA; import fedora.server.types.gen.DatastreamDef; import fedora.server.types.gen.MethodParmDef; import fedora.server.types.gen.MIMETypedStream; import fedora.server.types.gen.ObjectMethodsDef; import fedora.server.types.gen.ObjectProfile; import fedora.server.types.gen.RepositoryInfo; import fedora.server.types.gen.Property; /** * A simple example of a SOAP client that makes calls to the Fedora SOAP * interfaces (API-A and API-M). * * NOTE: * This class is outdated and uses demo objects that no longer exist. * Future releases will not include this class. * * @deprecated as of release 3.3 * @author Sandy Payette */ public class DemoSOAPClient implements Constants { private static FedoraAPIM APIM; private static FedoraAPIA APIA; private static HashMap s_repoInfo=new HashMap(); public DemoSOAPClient(String protocol, String host, int port, String user, String pass, String context) throws Exception { // Use the FedoraClient utility to get SOAP stubs. // These SOAP stubs enable the client to connect to a Fedora repository // via the API-A and API-M web service interfaces. String baseURL = protocol + "://" + host + ":" + port + "/" + context; FedoraClient fc = new FedoraClient(baseURL, user, pass); APIA=fc.getAPIA(); APIM=fc.getAPIM(); } public RepositoryInfo describeRepository() throws RemoteException { // make the SOAP call on API-A using the connection stub RepositoryInfo repoinfo = APIA.describeRepository(); // print results System.out.println("SOAP Request: describeRepository..."); System.out.println("SOAP Response: repository version = " + repoinfo.getRepositoryVersion()); System.out.println("SOAP Response: repository name = " + repoinfo.getRepositoryName()); System.out.println("SOAP Response: repository pid namespace = " + repoinfo.getRepositoryPIDNamespace()); System.out.println("SOAP Response: repository default export = " + repoinfo.getDefaultExportFormat()); System.out.println("SOAP Response: repository base URL = " + repoinfo.getRepositoryBaseURL()); System.out.println("SOAP Response: repository OAI namespace = " + repoinfo.getOAINamespace()); System.out.println("SOAP Response: repository sample OAI identifier = " + repoinfo.getSampleOAIIdentifier()); System.out.println("SOAP Response: repository sample OAI URL = " + repoinfo.getSampleOAIURL()); System.out.println("SOAP Response: repository sample access URL = " + repoinfo.getSampleAccessURL()); System.out.println("SOAP Response: repository sample search URL = " + repoinfo.getSampleSearchURL()); System.out.println("SOAP Response: repository sample PID = " + repoinfo.getSamplePID()); return repoinfo; } public String ingest(InputStream ingestStream, String ingestFormat, String logMessage) throws RemoteException, IOException { // prep ByteArrayOutputStream out=new ByteArrayOutputStream(); pipeStream(ingestStream, out, 4096); // make the SOAP call on API-M using the connection stub String pid = APIM.ingest(out.toByteArray(), ingestFormat, logMessage); System.out.println("SOAP Request: ingest..."); System.out.println("SOAP Response: pid = " + pid); return pid; } public String addDatastream(String pid, String dsID, String[] altIDs, String dsLabel, boolean versionable, String dsMIME, String formatURI, String dsLocation, String dsControlGroup, String dsState, String checksumType, String checksum, String logMessage) throws RemoteException { // make the SOAP call on API-M using the connection stub String datastreamID = APIM.addDatastream( pid, dsID, altIDs, dsLabel, versionable, dsMIME, formatURI, dsLocation, dsControlGroup, dsState, checksumType, checksum, logMessage); System.out.println("SOAP Request: addDatastream..."); System.out.println("SOAP Response: datastreamID = " + datastreamID); return datastreamID; } public String modifyDatastreamByReference(String pid, String dsID, String[] altIDs, String dsLabel, String dsMIME, String formatURI, String dsLocation, String checksumType, String checksum, String logMessage, boolean force) throws RemoteException { // make the SOAP call on API-M using the connection stub String datastreamID = APIM.modifyDatastreamByReference( pid, dsID, altIDs, dsLabel, dsMIME, formatURI, dsLocation, checksumType, checksum, logMessage, force); System.out.println("SOAP Request: modifyDatastreamByReference..."); System.out.println("SOAP Response: datastreamID = " + datastreamID); return datastreamID; } public String[] purgeDatastream(String pid, String dsID, String startDate, String endDate, String logMessage, boolean force) throws RemoteException { // make the SOAP call on API-M using the connection stub String[] dateTimeStamps = APIM.purgeDatastream( pid, dsID, startDate, endDate, logMessage, force); System.out.println("SOAP Request: purgeDatastream..."); return dateTimeStamps; } public String purgeObject(String pid, String logMessage, boolean force) throws RemoteException { // make the SOAP call on API-M using the connection stub String purgeDateTime = APIM.purgeObject(pid, logMessage, force); System.out.println("SOAP Request: purgeObject..."); System.out.println("SOAP Response: purge dateTime = " + purgeDateTime); return purgeDateTime; } public byte[] export(String pid, String format, String exportContext, OutputStream outStream) throws RemoteException, IOException { // make the SOAP call on API-M byte[] objectXML = APIM.export(pid, format, exportContext); // serialize the object XML to the specified output stream try { // use Xerces to pretty print the xml, assuming it's well formed DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder=factory.newDocumentBuilder(); Document doc=builder.parse(new ByteArrayInputStream(objectXML)); OutputFormat fmt=new OutputFormat("XML", "UTF-8", true); fmt.setIndent(2); fmt.setLineWidth(120); fmt.setPreserveSpace(false); XMLSerializer ser=new XMLSerializer(outStream, fmt); ser.serialize(doc); } catch (Exception e) { System.out.println("Error on export while serializing object XML." + e.getClass().getName() + " : " + e.getMessage()); } finally { outStream.close(); } // print results System.out.println("SOAP Request: export..."); System.out.println("SOAP Response: see result serialized in XML export file."); return objectXML; } public byte[] getObjectXML(String pid) throws RemoteException { // make the SOAP call on API-M byte[] objectXML = APIM.getObjectXML(pid); // print results return objectXML; } /** * Copies the contents of an InputStream to an OutputStream, then closes * both. * * @param in The source stream. * @param out The target stram. * @param bufSize Number of bytes to attempt to copy at a time. * @throws IOException If any sort of read/write error occurs on either * stream. */ public static void pipeStream(InputStream in, OutputStream out, int bufSize) throws IOException { try { byte[] buf = new byte[bufSize]; int len; while ( ( len = in.read( buf ) ) > 0 ) { out.write( buf, 0, len ); } } finally { try { in.close(); out.close(); } catch (IOException e) { System.err.println("WARNING: Could not close stream."); } } } public static void main(String[] args) { try { if (args.length==5 || args.length==6) { if (!args[0].equals("http") && !args[0].equals("https")) { throw new Exception("Protocol must be either \"http\" or \"https\". Value specified was: \""+args[0]+"\"."); } System.out.println("\n"); System.out.println("Protocol: " + args[0]); System.out.println("Host: " + args[1]); System.out.println("Port: " + args[2]); System.out.println("Username: " + args[3]); System.out.println("Password: " + args[4]); String context = Constants.FEDORA_DEFAULT_APP_CONTEXT; if (args.length == 6){ System.out.println("Context: " + args[5] + "\n"); context = args[5]; } // Instantiate the demo client. // This will set up connection stubs for making SOAP requests on API-A and API-M DemoSOAPClient caller = new DemoSOAPClient(args[0], args[1], new Integer(args[2]).intValue(), args[3], args[4], context); //************************************************************** //******** STEP 1 : get info about the repository //************************************************************** System.out.println("\nTest describeRepository.........................................."); RepositoryInfo repoinfo = caller.describeRepository(); //************************************************************** // ******** STEP 2 purge test objects if they already exist //************************************************************** String purgeDate=null; try { purgeDate = caller.purgeObject( "test:100", // the object pid "purge object", // an optional log message about the change false); // do not force changes that break ref integrity } catch (Exception e) { System.out.println("Hack...just ignore failures since objects may not exist yet." + e.getMessage()); } try { purgeDate = caller.purgeObject( "test:28", // the object pid "purge object", // an optional log message about the change false); // do not force changes that break ref integrity } catch (Exception e) { System.out.println("Hack...just ignore failures since objects may not exist yet." + e.getMessage()); } try { purgeDate = caller.purgeObject( "test:27", // the object pid "purge object", // an optional log message about the change false); // do not force changes that break ref integrity } catch (Exception e) { System.out.println("Hack...just ignore failures since objects may not exist yet." + e.getMessage()); } //************************************************************** //******** STEP 3: ingest the test objects //************************************************************** FileInputStream inStream=null; String ingestPID=null; System.out.println("\nTest ingest......................................................"); File ingestFile=new File("TestIngestFiles/sdef_test_27.xml"); try { inStream=new FileInputStream(ingestFile); } catch (IOException ioe) { System.out.println("Error on ingest file inputstream: " + ioe.getMessage()); ioe.printStackTrace(); } ingestPID = caller.ingest(inStream, FOXML1_1.uri, "ingest of test sdef"); System.out.println("Finished test ingest of sdef object: " + ingestPID); System.out.println("\nTest ingest......................................................"); ingestFile=new File("TestIngestFiles/sdep_test_28.xml"); inStream=null; try { inStream=new FileInputStream(ingestFile); } catch (IOException ioe) { System.out.println("Error on ingest file inputstream: " + ioe.getMessage()); ioe.printStackTrace(); } ingestPID = caller.ingest(inStream, FOXML1_1.uri, "ingest of test deployment"); System.out.println("Finished test ingest of deployment object: " + ingestPID); System.out.println("\nTest ingest......................................................"); ingestFile=new File("TestIngestFiles/obj_test_100.xml"); inStream=null; try { inStream=new FileInputStream(ingestFile); } catch (IOException ioe) { System.out.println("Error on ingest file inputstream: " + ioe.getMessage()); ioe.printStackTrace(); } ingestPID = caller.ingest(inStream, FOXML1_1.uri, "ingest of test object"); System.out.println("Finished test ingest of data object: " + ingestPID); System.out.println("\nTest ingest......................................................"); ingestFile=new File("TestIngestFiles/test_UVA_STD_IMAGE.xml"); inStream=null; try { inStream=new FileInputStream(ingestFile); } catch (IOException ioe) { System.out.println("Error on ingest file inputstream: " + ioe.getMessage()); ioe.printStackTrace(); } ingestPID = caller.ingest(inStream, FOXML1_1.uri, "ingest of test object"); System.out.println("Finished test ingest of cmodel object: " + ingestPID); //************************************************************** //******** STEP 4: add a datastream to the object //************************************************************** System.out.println("\nTest add datastream.............................................."); String[] altIDs = new String[] {"id1", "id2", "id3"}; String datastreamID = caller.addDatastream( ingestPID, // the object pid "MY-DS", // user-assigned datastream name or id altIDs, "Add my test datastream", // user-assigned label true, // in version 2.0 always set datastream versioning to true "image/gif", // mime type of the datastream content "info:fedora/format/myformat", // an optional format URI "http://www.cs.cornell.edu/payette/images/sjcomp.gif", // URL for content "E", // type E for External Referenced Datastream "A", // datastream state is A for Active null, // datastream checksumType null, // datastream checksum "added new datastream MY-DS"); // log message //************************************************************** //******** STEP 5: modify a datastream //************************************************************** // modify the datastream using null to indicate which attributes should stay the same. System.out.println("\nFirst test of modify datastream ................................."); String modDSID = caller.modifyDatastreamByReference( ingestPID, // the object pid "MY-DS", // user-assigned datastream name or id null, // altIDs (no change) "modify-1 of my test datastream", // new user-assigned label null, // MIME type (no change) null, // new formatURI (no change) null, // new URL for content (no change) null, // new checksumType null, // new checksum "first modify to change label only", // an optional log message about the change false); // do not force changes that break ref integrity //************************************************************** //******** STEP 6: modify a datastream again //************************************************************** // again, modify the datastream and test setting attributes to empty strings. // NOTE: attempt to set system required attribute to empty will default to no change. System.out.println("\nSecond test of modify datastream................................."); modDSID = caller.modifyDatastreamByReference( ingestPID, // the object pid "MY-DS", // user-assigned datastream name or id new String[0], // altIDs (empty array) "", // new user-assigned label "", // MIME type (empty) "", // new formatURI (empty) "", // new URL for content (no change since required field cannot be emptied) null, // new checksumType null, // new checksum "second modify to empty all non-required fields", // an optional log message about the change false); // do not force changes that break ref integrity //************************************************************** //******** STEP 7: purge a datastream //************************************************************** System.out.println("\nTest of purge datastream........................................."); String[] dateTimeStamps = caller.purgeDatastream( ingestPID, // the object pid "MY-DS", // user-assigned datastream name or id "", "", // end date to purge versions before (null/empty to purge all versions) "purge datastream", // an optional log message about the change false); // do not force changes that break ref integrity //************************************************************** //******** STEP 8: export the demo object //************************************************************** System.out.println("\nTest of export object............................................"); File exportFile = new File("demo-export.xml"); FileOutputStream outStream = null; try { outStream = new FileOutputStream(exportFile); } catch (IOException ioe) { System.out.println("Error on export output stream: " + ioe.getMessage()); ioe.printStackTrace(); } byte[] objectXML = caller.export(ingestPID, FOXML1_1.uri, null, outStream); //************************************************************** //******** NOW TEST API-A METHODS //************************************************************** //************************************************************** //******** STEP 9: listDatastreams for demo object demo:11 //************************************************************** System.out.println("\nTest of listDatastream..........................................."); listDatastreams(); //************************************************************** //******** STEP 10: listMethods for demo object demo:11 //************************************************************** System.out.println("\nTest of listMethods.............................................."); listMethods(); //************************************************************** //******** STEP 11: get the object profile for demo object demo:11 //************************************************************** System.out.println("\nTest of getObjectProfile........................................."); getObjectProfile(); //************************************************************** //******** STEP 12: get several datastreams from various demo objects //************************************************************** System.out.println("\nTest of getDatastreamDissemination..............................."); getDatastreamDissemination(); //************************************************************** //******** STEP 13: get several disseminations from various demo objects //************************************************************** System.out.println("\nTest of getDissemination........................................."); getDissemination(); //************************************************************** //******** STEP 14: get object history the demo object demo:11 //************************************************************** System.out.println("\nTest of getObjectHistory........................................."); getObjectHistory(); } else { System.out.println("Number of arguments must be equal to 5."); System.out.println("Usage: run-demo-soapclient protocol host port username password"); System.out.println("Demo soapclient requires that demo objects are already ingested in repository \n"); } } catch (Exception e) { System.out.println("Exception in main: " + e.getMessage()); e.printStackTrace(); } } public static void listDatastreams() throws Exception { DatastreamDef[] dsDefs = APIA.listDatastreams("demo:11", null); System.out.println("SOAP Request: listDatastreams..."); System.out.println("SOAP Response: see results below."); verifyDatastreamDefs(dsDefs, "SOAP Response: listDatastream: "); } public static void listMethods() throws Exception { ObjectMethodsDef[] methodDefs = APIA.listMethods("demo:11", null); System.out.println("SOAP Request: listMethods..."); System.out.println("SOAP Response: see results below."); verifyObjectMethods(methodDefs, "SOAP Response: listMethods: "); } public static void getDatastreamDissemination() throws Exception { // test for DC datastream MIMETypedStream ds = null; ds = APIA.getDatastreamDissemination("demo:11", "DC", null); System.out.println("SOAP Request: getDatastreamDissemination for DC datastream of demo object demo:11..."); String dsXML = new String(ds.getStream(), "UTF-8"); System.out.println("SOAP Response: GetDatastreamDissemination Object:demo:11 Datastream:DC succeeded."); System.out.println("SOAP Response: DC datastream contents: \n"+dsXML); // test for type X datastream ds = APIA.getDatastreamDissemination("demo:11", "TECH1", null); System.out.println("\nSOAP Request: getDatastreamDissemination for TECH1 datastream of demo object demo:11..."); dsXML = new String(ds.getStream(), "UTF-8"); System.out.println("SOAP Response: GetDatastreamDissemination Object:demo:11 Datastream:TECH1 succeeded."); System.out.println("SOAP Response: TECH1 datastream contents: \n"+dsXML); // test for type E datastream ds = APIA.getDatastreamDissemination("demo:11", "MRSID", null); System.out.println("\nSOAP Request: getDatastreamDissemination for MRSID datastream of demo object demo:11..."); System.out.println("SOAP Response: GetDatastreamDissemination Object:demo:11 Datastream:MRSID succeeded."); System.out.println("SOAP Response: MRSID datastream contents: BINARY DATA "+ds); // test for type R datastream ds = APIA.getDatastreamDissemination("demo:30", "THUMBRES_IMG", null); System.out.println("\nSOAP Request: getDatastreamDissemination for THUMBRES_IMG datastream of demo object demo:30..."); System.out.println("SOAP Response: GetDatastreamDissemination Object:demo:30 Datastream:THUMBRES_IMG succeeded."); System.out.println("SOAP Response: THUMBRES_IMG datastream contents: BINARY DATA "+ds); // test for type M datastream ds = APIA.getDatastreamDissemination("demo:5", "THUMBRES_IMG", null); System.out.println("\nSOAP Request: getDatastreamDissemination for THUMBRES_IMG datastream of demo object demo:5..."); System.out.println("SOAP Response: GetDatastreamDissemination Object:demo:5 Datastream:THUMBRES_IMG succeeded."); System.out.println("SOAP Response: THUMBRES_IMG datastream contents: BINARY DATA "+ds); } public static void getObjectProfile() throws Exception { ObjectProfile profile = APIA.getObjectProfile("demo:11", null); System.out.println("SOAP Request: getObjectProfile for demo object demo:11..."); System.out.println("SOAP Response: PID: "+profile.getPid()); System.out.println("SOAP Response: ObjectLabel: "+profile.getObjLabel()); System.out.println("SOAP Response: CreateDate: "+profile.getObjCreateDate()); System.out.println("SOAP Response: LastModDate: "+profile.getObjLastModDate()); System.out.println("SOAP Response: DissIndexViewURL: "+profile.getObjDissIndexViewURL()); System.out.println("SOAP Response: ItemIndexViewURL: "+profile.getObjItemIndexViewURL()); } public static void getObjectHistory() throws Exception { String[] timestamps = APIA.getObjectHistory("demo:11"); System.out.println("SOAP Request: getObjectHistory for demo object demo:11..."); for (int i=0; i<timestamps.length; i++) { System.out.println("SOAP Response: object:demo:11 changeDate["+i+"]: "+timestamps[i]); } } public static void getDissemination() throws Exception { // test dissemination of the Default Disseminator MIMETypedStream diss = null; diss = APIA.getDissemination("demo:5", "fedora-system:3", "viewDublinCore", new Property[0], null); System.out.println("SOAP Request: getDissemination for method viewDublinCore of demo object demo:11..."); String dsXML = new String(diss.getStream(), "UTF-8"); System.out.println("SOAP Response: GetDissemination Object:demo:11 Method:viewDublinCore succeeded."); System.out.println("SOAP Response: Dissemination results: \n"+dsXML); // test dissemination of getThumb method with no parameters diss = APIA.getDissemination("demo:5", "demo:1", "getThumbnail", new Property[0], null); System.out.println("\nSOAP Request: getDissemination for method getThumbnail of demo object demo:5..."); System.out.println("SOAP Response: GetDissemination Object:demo:5 Method:getThumbnail succeeded."); System.out.println("SOAP Response: Dissemination results: BINARY DATA "+diss); // test dissemination using resizeImage method with parameters Property[] parms = new Property[4]; Property p = new Property(); p.setName("width"); p.setValue("100"); parms[0] = p; Property p2 = new Property(); p2.setName("height"); p2.setValue("100"); parms[1] = p2; Property p3 = new Property(); p3.setName("x"); p3.setValue("100"); parms[2] = p3; Property p4 = new Property(); p4.setName("y"); p4.setValue("100"); parms[3] = p4; diss = APIA.getDissemination("demo:29", "demo:27", "cropImage", parms, null); System.out.println("\nSOAP Request: getDissemination for method cropImage of demo object demo:29..."); System.out.println("SOAP Response: GetDissemination Object:demo:29 Method:cropImage succeeded."); System.out.println("SOAP Response: Dissemination results: BINARY DATA "+diss); } public static void verifyDatastreamDefs(DatastreamDef[] dsDefArray, String msg) throws Exception { String dsID = null; String label = null; String mimeType = null; DatastreamDef dsDef = null; for (int i=0; i<dsDefArray.length; i++) { dsDef = dsDefArray[i]; dsID = dsDef.getID(); label = dsDef.getLabel(); mimeType = dsDef.getMIMEType(); System.out.println(msg + " datastreamDef["+i+"] " + "dsID: "+dsID); System.out.println(msg + " datastreamDef["+i+"] " + "label: '"+label+"'"); System.out.println(msg + " datastreamDef["+i+"] " + "mimeType: "+mimeType); } } public static void verifyObjectMethods(ObjectMethodsDef[] methodDefsArray, String msg) throws Exception { String sDefPID = null; String methodName = null; MethodParmDef[] parms = null; ObjectMethodsDef methodDef = null; for (int i=0; i<methodDefsArray.length; i++) { methodDef = methodDefsArray[i]; sDefPID = methodDef.getServiceDefinitionPID(); methodName = methodDef.getMethodName(); parms = methodDef.getMethodParmDefs(); System.out.println(msg + " methodDef["+i+"] " + "sDefPID: "+sDefPID); System.out.println(msg + " methodDef["+i+"] " + "methodName: '"+methodName+"'"); for (int j=0; j<parms.length; j++) { MethodParmDef p = parms[j]; System.out.println(msg + " methodDef["+i+"] " + "parmName["+j+"] "+p.getParmName()); } } } }