/**
* The FreeBSD Copyright
* Copyright 1994-2008 The FreeBSD Project. All rights reserved.
* Copyright (C) 2013-2017 Philip Helger philip[at]helger[dot]com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the FreeBSD Project.
*/
package com.helger.as2lib.partner.xml;
import java.io.File;
import java.io.InputStream;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.WillClose;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.helger.as2lib.exception.OpenAS2Exception;
import com.helger.as2lib.exception.WrappedOpenAS2Exception;
import com.helger.as2lib.params.InvalidParameterException;
import com.helger.as2lib.partner.Partnership;
import com.helger.as2lib.partner.PartnershipMap;
import com.helger.as2lib.session.IAS2Session;
import com.helger.as2lib.util.IOHelper;
import com.helger.as2lib.util.IStringMap;
import com.helger.as2lib.util.StringMap;
import com.helger.as2lib.util.XMLHelper;
import com.helger.commons.collection.ext.ICommonsOrderedMap;
import com.helger.commons.io.file.FileHelper;
import com.helger.commons.string.StringHelper;
import com.helger.xml.microdom.IMicroDocument;
import com.helger.xml.microdom.IMicroElement;
import com.helger.xml.microdom.MicroDocument;
import com.helger.xml.microdom.serialize.MicroReader;
import com.helger.xml.microdom.serialize.MicroWriter;
/**
* original author unknown this release added logic to store partnerships and
* provide methods for partner/partnership command line processor
*
* @author joseph mcverry
*/
public class XMLPartnershipFactory extends AbstractPartnershipFactoryWithPartners
{
public static final String ATTR_FILENAME = "filename";
public static final String ATTR_DISABLE_BACKUP = "disablebackup";
private static final String PARTNER_NAME = Partner.PARTNER_NAME;
private static final String PARTNERSHIP_NAME = Partner.PARTNER_NAME;
private static final Logger s_aLogger = LoggerFactory.getLogger (XMLPartnershipFactory.class);
public void setFilename (final String filename)
{
setAttribute (ATTR_FILENAME, filename);
}
public String getFilename () throws InvalidParameterException
{
return getAttributeAsStringRequired (ATTR_FILENAME);
}
@Override
public void initDynamicComponent (@Nonnull final IAS2Session session,
@Nullable final IStringMap parameters) throws OpenAS2Exception
{
super.initDynamicComponent (session, parameters);
refresh ();
}
public void refresh () throws OpenAS2Exception
{
try
{
load (FileHelper.getInputStream (new File (getFilename ())));
}
catch (final Exception ex)
{
throw WrappedOpenAS2Exception.wrap (ex);
}
}
protected void load (@Nullable @WillClose final InputStream aIS) throws OpenAS2Exception
{
final PartnerMap aNewPartners = new PartnerMap ();
final PartnershipMap aNewPartnerships = new PartnershipMap ();
if (aIS != null)
{
final IMicroDocument aDocument = MicroReader.readMicroXML (aIS);
final IMicroElement root = aDocument.getDocumentElement ();
for (final IMicroElement eRootNode : root.getAllChildElements ())
{
final String sNodeName = eRootNode.getTagName ();
if (sNodeName.equals ("partner"))
{
final Partner aNewPartner = loadPartner (eRootNode);
aNewPartners.addPartner (aNewPartner);
}
else
if (sNodeName.equals ("partnership"))
{
final Partnership aNewPartnership = loadPartnership (eRootNode, aNewPartners);
if (aNewPartnerships.getPartnershipByName (aNewPartnership.getName ()) != null)
throw new OpenAS2Exception ("Partnership with name '" +
aNewPartnership.getName () +
"' is defined more than once");
aNewPartnerships.addPartnership (aNewPartnership);
}
else
s_aLogger.warn ("Invalid element '" + sNodeName + "' in XML partnership file");
}
}
setPartners (aNewPartners);
setPartnerships (aNewPartnerships);
}
protected void loadPartnershipAttributes (@Nonnull final IMicroElement aNode,
@Nonnull final Partnership aPartnership) throws OpenAS2Exception
{
final String sNodeName = "attribute";
final String sNodeKeyName = "name";
final String sNodeValueName = "value";
final ICommonsOrderedMap <String, String> aAttributes = XMLHelper.mapAttributeNodes (aNode,
sNodeName,
sNodeKeyName,
sNodeValueName);
aPartnership.addAllAttributes (aAttributes);
}
@Nonnull
public Partner loadPartner (@Nonnull final IMicroElement ePartner) throws OpenAS2Exception
{
// Name is required
final StringMap aAttrs = XMLHelper.getAllAttrsWithLowercaseNameWithRequired (ePartner, PARTNER_NAME);
return new Partner (aAttrs);
}
protected void loadPartnerIDs (@Nonnull final IMicroElement ePartnership,
@Nonnull final IPartnerMap aAllPartners,
@Nonnull final Partnership aPartnership,
final boolean bIsSender) throws OpenAS2Exception
{
final String sPartnerType = bIsSender ? "sender" : "receiver";
final IMicroElement ePartner = ePartnership.getFirstChildElement (sPartnerType);
if (ePartner == null)
throw new OpenAS2Exception ("Partnership '" +
aPartnership.getName () +
"' is missing '" +
sPartnerType +
"' child element");
final IStringMap aPartnerAttrs = XMLHelper.getAllAttrsWithLowercaseName (ePartner);
// check for a partner name, and look up in partners list if one is found
final String sPartnerName = aPartnerAttrs.getAttributeAsString (PARTNER_NAME);
if (sPartnerName != null)
{
// Resolve name from existing partners
final IPartner aPartner = aAllPartners.getPartnerOfName (sPartnerName);
if (aPartner == null)
{
throw new OpenAS2Exception ("Partnership '" +
aPartnership.getName () +
"' has a non-existing " +
sPartnerType +
" partner: '" +
sPartnerName +
"'");
}
// Set all attributes from the stored partner
if (bIsSender)
aPartnership.addSenderIDs (aPartner.getAllAttributes ());
else
aPartnership.addReceiverIDs (aPartner.getAllAttributes ());
}
// copy all other (existing) attributes to the partner id map - overwrite
// the ones present in the partner element
if (bIsSender)
aPartnership.addSenderIDs (aPartnerAttrs.getAllAttributes ());
else
aPartnership.addReceiverIDs (aPartnerAttrs.getAllAttributes ());
}
@Nonnull
public Partnership loadPartnership (@Nonnull final IMicroElement ePartnership,
@Nonnull final IPartnerMap aAllPartners) throws OpenAS2Exception
{
// Name attribute is required
final IStringMap aPartnershipAttrs = XMLHelper.getAllAttrsWithLowercaseNameWithRequired (ePartnership,
PARTNERSHIP_NAME);
final Partnership aPartnership = new Partnership (aPartnershipAttrs.getAttributeAsString (PARTNERSHIP_NAME));
// load the sender and receiver information
loadPartnerIDs (ePartnership, aAllPartners, aPartnership, true);
loadPartnerIDs (ePartnership, aAllPartners, aPartnership, false);
// read in the partnership attributes
loadPartnershipAttributes (ePartnership, aPartnership);
return aPartnership;
}
@Nonnull
private File _getUniqueBackupFile (final String sFilename)
{
long nIndex = 0;
File aBackupFile;
do
{
aBackupFile = new File (sFilename + '.' + StringHelper.getLeadingZero (nIndex, 7));
nIndex++;
} while (aBackupFile.exists ());
return aBackupFile;
}
/**
* Store the current status of the partnerships to a file.
*
* @throws OpenAS2Exception
* In case of an error
*/
public void storePartnership () throws OpenAS2Exception
{
final String sFilename = getFilename ();
if (!containsAttribute (ATTR_DISABLE_BACKUP))
{
final File aBackupFile = _getUniqueBackupFile (sFilename);
s_aLogger.info ("backing up " + sFilename + " to " + aBackupFile.getName ());
final File aSourceFile = new File (sFilename);
IOHelper.getFileOperationManager ().renameFile (aSourceFile, aBackupFile);
}
final IMicroDocument aDoc = new MicroDocument ();
final IMicroElement eRoot = aDoc.appendElement ("partnerships");
for (final IPartner aPartner : getAllPartners ())
{
final IMicroElement ePartner = eRoot.appendElement ("partner");
for (final Map.Entry <String, String> aAttr : aPartner)
ePartner.setAttribute (aAttr.getKey (), aAttr.getValue ());
}
for (final Partnership aPartnership : getAllPartnerships ())
{
final IMicroElement ePartnership = eRoot.appendElement ("partnership");
ePartnership.setAttribute (PARTNERSHIP_NAME, aPartnership.getName ());
final IMicroElement eSender = ePartnership.appendElement ("sender");
for (final Map.Entry <String, String> aAttr : aPartnership.getAllSenderIDs ())
eSender.setAttribute (aAttr.getKey (), aAttr.getValue ());
final IMicroElement eReceiver = ePartnership.appendElement ("receiver");
for (final Map.Entry <String, String> aAttr : aPartnership.getAllReceiverIDs ())
eReceiver.setAttribute (aAttr.getKey (), aAttr.getValue ());
for (final Map.Entry <String, String> aAttr : aPartnership.getAllAttributes ())
ePartnership.appendElement ("attribute")
.setAttribute ("name", aAttr.getKey ())
.setAttribute ("value", aAttr.getValue ());
}
if (MicroWriter.writeToFile (aDoc, new File (sFilename)).isFailure ())
throw new OpenAS2Exception ("Failed to write to file " + sFilename);
}
}