/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved. This software is licensed
* under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1] [1]
* http://www.gnu.org/licenses/gpl.txt
*/
package hk.hku.cecid.corvus.partnership;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import hk.hku.cecid.edi.as2.dao.PartnershipDAO;
import hk.hku.cecid.edi.as2.dao.PartnershipDVO;
import hk.hku.cecid.piazza.commons.Sys;
import hk.hku.cecid.piazza.commons.dao.DAOException;
import hk.hku.cecid.piazza.commons.dao.DAOFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXException;
/**
* The <code>AS2Partnership</code> is the utilities for maintaining the partnership
* of AS2. In current version, it support addition or deletion of the partnership.
*
* @author kochiu, Twinsen Tsang (modifiers)
*
* @see #createAS2Partnership(String)
* @see #removeAS2Partnership(String)
*/
public class AS2Partnership {
/**
* The entry point for CLI.
*
* @param args
* The arguments have two parametes. The first one is the partnership maintenance
* which is either "-a" (add) or "-d" (delete). The second one is the
* xml file containing the partnership information. They are located
* at the "conf/as2.xml" relative to the program folders.
*/
public static void main(String[] args) {
if (args.length < 2) { printUsage(); return; }
String option = args[0];
String xmlFile = args[1];
try {
if ("-a".equals(option)) {
boolean result = createAS2Partnership(xmlFile);
System.out.println(result ? "Added partnership successfully." : "Cannont remove partnership.");
} else if ("-d".equals(option)) {
boolean result = removeAS2Partnership(xmlFile);
System.out.println(result ? "Removed partnership successfully." : "Cannont remove partnership.");
} else {
printUsage();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printUsage(){
System.out.println("Usage : java AS2Partnership -options <xml_file_path>");
System.out.println("Options :");
System.out.println("\t -a \t Add partnership");
System.out.println("\t -d \t Delete partnership");
}
/**
* Create a AS2 partnership with the configuration defined in the <code>XMLFile</code>.
*
* @param xmlFile
* The partnership XML instance file. It is located at "/data/as2.xml".
* @return
* true if the removal operation ran successfully.
* @throws DAOException
* Error in persistence connectivity.
* @throws DocumentException
* Error in reading the parameter in the <code>xmlFile</code>.
* @throws SAXException
* Error in parsing the <code>xmlFile</code>.
* @throws IOException
*/
public static boolean createAS2Partnership(String xmlFile)
throws DAOException, DocumentException, SAXException, IOException
{
Element e = getRootElementFromFile(xmlFile);
// Checking whether there is any field violating the AS2 specification.
List errors = fieldChecking(e);
if (errors.size() > 0) {
for (int i = 0; i < errors.size(); i++)
System.out.println(errors.get(i));
return false;
}
/*
* Create an DAOFactory for creating AS2 partnership, you may refer
* to the configuration file for the setting of "as2-daofactory" at
* "conf/partnership.as2-dao.xml"
*/
DAOFactory as2DAOFactory = (DAOFactory) Sys.main.getComponent("as2-daofactory");
PartnershipDAO partnershipDao = (PartnershipDAO) as2DAOFactory.createDAO(PartnershipDAO.class);
PartnershipDVO dvo = (PartnershipDVO) partnershipDao.createDVO();
String pID = e.attributeValue("id");
dvo.setPartnershipId(pID);
// There is the same database record found in the persistence, warning the user for
// overwriting the record.
if (partnershipDao.retrieve(dvo)){
System.out.println("Existing partnership with id: " + pID + " found. Removing it.");
partnershipDao.remove(dvo);
// create again.
dvo = (PartnershipDVO) partnershipDao.createDVO();
}
Element params = e.element("parameters");
dvo.setPartnershipId(pID);
// AS2 Specific information.
dvo.setAs2From (params.elementText("as2From"));
dvo.setAs2To (params.elementText("as2To"));
dvo.setSubject (params.elementText("subject"));
// AS2 Devliery information.
dvo.setRecipientAddress(params.elementText("recipientAddress"));
// Requires SSL for delivery ?
dvo.setIsHostnameVerified("true".equalsIgnoreCase(params.elementText("hostnameVerifiedInSsl")));
// Requires recipient sending back a receipt (ACK) ?
dvo.setIsReceiptRequired ("true".equalsIgnoreCase (params.elementText("requestMdn")));
// Requires the digitial signatures at the receipt send by recipient.
dvo.setIsReceiptSignRequired("true".equalsIgnoreCase(params.elementText("signedReceipt")));
// Requires receipt being sent using same connection or different connection.
dvo.setIsSyncReply("false".equalsIgnoreCase(params.elementText("asynchronousReceipt")));
// The URL that receipt is sent to when using different connection response mode.
dvo.setReceiptAddress(params.elementText("mdnReturnUrl"));
// Set whether compression is required for outgoing AS2 Message.
dvo.setIsOutboundCompressRequired("true".equalsIgnoreCase(params
.elementText("messageCompressionRequired")));
// AS2 Security-related information
// Set whether digital signatures is required for outgoing AS2 Message.
dvo.setIsOutboundSignRequired("true".equalsIgnoreCase(params.elementText("messageSigningRequired")));
// Set whether which signing algorithm is used. SHA1 or MD5.
if (params.elementText("signingAlgorithm") != null)
dvo.setSignAlgorithm(params.elementText("signingAlgorithm"));
// Set whether encryption is required for outgoing AS2 Message.
dvo.setIsOutboundEncryptRequired("true".equalsIgnoreCase(params
.elementText("messageEncryptionRequired")));
// Set wehther which encryption algorithm is used. 3DES or RC2.
if (params.elementText("encryptionAlgorithm") != null) {
dvo.setEncryptAlgorithm(params.elementText("encryptionAlgorithm"));
}
// Set the MIC (Message-Integrity-Check) algorithm. SHA1 or MD5.
if (params.elementText("micAlgorithm") != null)
dvo.setMicAlgorithm(params.elementText("micAlgorithm"));
// Load the public certificates for encryption.
dvo.setEncryptCert(Utilities.loadCert(params.elementText("certificateForEncryption")));
// Load the public certificates for signatures verification
// (ONLY for incoming message or requires signed receipt ).
dvo.setVerifyCert(Utilities.loadCert(params.elementText("certificateForVerification")));
// Set whether signing / encryption MUST be applied or not when receiving an AS2 Message.
dvo.setIsInboundSignRequired ("true".equalsIgnoreCase(params.elementText("messageSignatureEnforced")));
dvo.setIsInboundEncryptRequired("true".equalsIgnoreCase(params.elementText("messageEncryptionEnforced")));
// General delivery information
dvo.setRetries(Integer.parseInt(params.elementText("maximumRetries")));
dvo.setRetryInterval(Integer.parseInt(params.elementText("retryInterval")));
dvo.setIsDisabled(false);
// Create the partnership.
partnershipDao.create(dvo);
return true;
}
/**
* Checking whether there is any field in the partnership xml file
* violating the AS2 specification.
*
* @param root The root element in the partnership xml file.
* @return A list of string containing the error description. Empty list if no error has been found.
*/
private static List fieldChecking(Element root) {
Element params = root.element("parameters");
List errors = new ArrayList();
// When asynchronous reciept is set, then it MUST requests for receipt and
// the async return URL must not NULL.
if (Utilities.getBooleanValue(params, "asynchronousReceipt")){
if (!Utilities.getBooleanValue(params, "requestMdn"))
errors.add("Request MDN must be 'true' to enable the Asynchronous Receipt");
if (params.elementText("recipientAddress") == null)
errors.add("MDN Return URL must not be empty to enable the Asynchronous Receipt");
}
// When digital signatures is required, then it MUST requests for receipt and
// providing the public certificates for verifying the signatures.
if (Utilities.getBooleanValue(params, "signedReceipt")){
if (Utilities.getBooleanValue(params, "requestMdn"))
errors.add("Request MDN must be 'true' to enable the Signed Receipt");
try {
if (Utilities.loadCert(params.elementText("certificateForVerification")) == null)
errors.add("A certificate must be defined in 'certificateForVerification' to enable the Message Signing Required");
} catch (IOException ioe) {
errors.add("The certificate defined in 'certificateForVerification' cannot load to enable the Message Signing Required. Details : " + ioe.getMessage());
}
}
// When encryption is required, then It MUST provide the encryption algorithm and the
// public certificates used for encryption.
if (Utilities.getBooleanValue(params, "messageEncryptionRequired")) {
if (params.elementText("encryptionAlgorithm") == null)
errors.add("An encryption algorithm must be defined in 'encryptionAlgorithm' to enable the Message Encryption Required");
try {
if (Utilities.loadCert(params.elementText("certificateForEncryption")) == null)
errors.add("A certificate must be defined in 'certificateForEncryption' to enable the Message Encryption Required");
} catch (IOException ioe) {
errors.add("The certificate defined in 'certificateForEncryption' cannot load to enable the Message Encryption Required. Details : " + ioe.getMessage());
}
}
// When digital signatures is required for outgoing AS2 message, partnership MUST define
// use which signing algorithm.
if (Utilities.getBooleanValue(params, "messageSigningRequired")){
if (params.elementText("signingAlgorithm") == null)
errors.add("A signing algorithm must be defined in 'signingAlgorithm' to enable the Message Signing Required");
}
// When receipt is requested, partnership MUST define the MIC algorithm for check-sum.
if (Utilities.getBooleanValue(params, "requestMdn")){
if (params.elementText("micAlgorithm") == null)
errors.add("A MIC algorithm must be defined in 'micAlgorithm' to enable the Request MDN");
}
return errors;
}
/**
* Remove a particular partnership defined in the <code>xmlFile</code>.<br/><br/>
*
* Only the attributes <id> in the <code>xmlFile</code> will be used
* for removing partnership.
*
* @param xmlFile
* The partnership XML instance file. It is located at "/data/ebms.xml".
* @return
* true if the removal operation ran successfully.
* @throws DAOException
* Error in persistence connectivity.
* @throws DocumentException
* Error in reading the parameter in the <code>xmlFile</code>.
* @throws SAXException
* Error in parsing the <code>xmlFile</code>.
* @throws IOException
*
*/
public static boolean removeAS2Partnership(String xmlFile)
throws DAOException, DocumentException, FileNotFoundException, SAXException
{
Element root = getRootElementFromFile(xmlFile);
/*
* Create an DAOFactory for creating AS2 partnership, you may refer
* to the configuration file for the setting of "as2-daofactory" at
* "conf/partnership.as2-dao.xml"
*/
DAOFactory as2DAOFactory = (DAOFactory) Sys.main.getComponent("as2-daofactory");
PartnershipDAO partnershipDao = (PartnershipDAO) as2DAOFactory.createDAO(PartnershipDAO.class);
PartnershipDVO dvo = (PartnershipDVO) partnershipDao.createDVO();
String pidToRemove = root.attributeValue("id");
if (pidToRemove == null || "".equalsIgnoreCase(pidToRemove))
throw new DocumentException("Missing attribute <id> for deleting the partnership.");
// Set the id of the partnership to remove.
dvo.setPartnershipId(pidToRemove);
return partnershipDao.remove(dvo);
}
/**
* Read and parse the <code>xmlFile</code> and return the root element
* (document).
*
* @param xmlFile
* The partnership XML instance file. It is located at
* "/data/ebms.xml".
* @return The root element of the <code>xmlFile</code>.
* @throws SAXException
* Error in parsing the <code>xmlFile</code>.
* @throws DocumentException
* Error in reading the parameter in the <code>xmlFile</code>.
* @throws IOException
*/
private static Element getRootElementFromFile(String xmlFile)
throws SAXException, DocumentException, FileNotFoundException {
InputStream is = new FileInputStream(xmlFile);
SAXReader reader = new SAXReader();
// Setup the XSD validation features.
reader.setFeature("http://apache.org/xml/features/validation/schema",true);
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
reader.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", "data/as2.xsd");
Document doc = reader.read(is);
return doc.getRootElement();
}
}