/**
* Copyright (C) 2015-2017 jochenberger & Philip Helger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.helger.as2lib.partner.mongodb;
import java.util.Map.Entry;
import org.bson.Document;
import org.slf4j.Logger;
import com.helger.as2lib.AbstractDynamicComponent;
import com.helger.as2lib.exception.OpenAS2Exception;
import com.helger.as2lib.message.IMessage;
import com.helger.as2lib.message.IMessageMDN;
import com.helger.as2lib.params.MessageParameters;
import com.helger.as2lib.partner.CPartnershipIDs;
import com.helger.as2lib.partner.IPartnershipFactory;
import com.helger.as2lib.partner.Partnership;
import com.helger.as2lib.partner.PartnershipNotFoundException;
import com.helger.as2lib.util.IStringMap;
import com.helger.commons.annotation.CodingStyleguideUnaware;
import com.helger.commons.collection.ext.CommonsArrayList;
import com.helger.commons.collection.ext.CommonsHashMap;
import com.helger.commons.collection.ext.CommonsHashSet;
import com.helger.commons.collection.ext.ICommonsList;
import com.helger.commons.collection.ext.ICommonsMap;
import com.helger.commons.collection.ext.ICommonsSet;
import com.helger.commons.state.EChange;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.result.DeleteResult;
/**
* MongoDB based implementation of {@link IPartnershipFactory}
*
* @author jochenberger
*/
@CodingStyleguideUnaware
public class MongoDBPartnershipFactory extends AbstractDynamicComponent implements IPartnershipFactory {
private static final long serialVersionUID = -2282798646250446937L;
private static final String NAME_KEY = "name";
private static final String RECEIVER_IDS = "receiver-ids";
private static final String SENDER_IDS = "sender-ids";
private static final String ATTRIBUTES = "attributes";
private final MongoCollection <Document> partnerships;
private final Logger logger;
public MongoDBPartnershipFactory (final MongoCollection <Document> partnerships, final Logger logger) {
this.logger = logger;
partnerships.createIndex (new Document (NAME_KEY, Integer.valueOf (1)), new IndexOptions ().unique (true));
this.partnerships = partnerships;
}
@Override
public EChange addPartnership (final Partnership aPartnership) throws OpenAS2Exception {
partnerships.insertOne (toDocument (aPartnership));
return EChange.CHANGED;
}
@Override
public EChange removePartnership (final Partnership aPartnership) throws OpenAS2Exception {
final DeleteResult result = partnerships.deleteOne (new Document (NAME_KEY, aPartnership.getName ()));
if (result.getDeletedCount () >= 1l) {
return EChange.CHANGED;
}
return EChange.UNCHANGED;
}
@Override
public void updatePartnership (final IMessage aMsg, final boolean bOverwrite) throws OpenAS2Exception {
// Fill in any available partnership information
final Partnership aPartnership = getPartnership (aMsg.getPartnership ());
logger.debug ("Updating partnership {}", aPartnership);
// Update partnership data of message with the stored ones
aMsg.getPartnership ().copyFrom (aPartnership);
// Set attributes
if (bOverwrite) {
final String sSubject = aPartnership.getAttribute (CPartnershipIDs.PA_SUBJECT);
if (sSubject != null) {
aMsg.setSubject (new MessageParameters (aMsg).format (sSubject));
}
}
}
@Override
public void updatePartnership (final IMessageMDN aMdn, final boolean bOverwrite) throws OpenAS2Exception {
final Partnership aPartnership = getPartnership (aMdn.getPartnership ());
aMdn.getPartnership ().copyFrom (aPartnership);
}
@Override
public Partnership getPartnership (final Partnership aPartnership) throws OpenAS2Exception {
Partnership aRealPartnership = getPartnershipByName (aPartnership.getName ());
if (aRealPartnership == null) {
// Found no partnership by name
aRealPartnership = getPartnershipByID (aPartnership.getAllSenderIDs (), aPartnership.getAllReceiverIDs ());
}
if (aRealPartnership == null) {
throw new PartnershipNotFoundException (aPartnership);
}
return aRealPartnership;
}
private Partnership getPartnershipByID (final IStringMap allSenderIDs, final IStringMap allReceiverIDs) {
Document filter = new Document ();
for (final Entry <String, String> entry : allSenderIDs) {
filter.append (SENDER_IDS + "." + entry.getKey (), entry.getValue ());
}
for (final Entry <String, String> entry : allReceiverIDs) {
filter.append (RECEIVER_IDS + "." + entry.getKey (), entry.getValue ());
}
Partnership result = partnerships.find (filter).map (MongoDBPartnershipFactory::toPartnership).first ();
if (result != null) {
return result;
}
// try the other way around, maybe we're receiving a response
// TODO is this really a good idea?
filter = new Document ();
for (final Entry <String, String> entry : allSenderIDs) {
filter.append (RECEIVER_IDS + "." + entry.getKey (), entry.getValue ());
}
for (final Entry <String, String> entry : allReceiverIDs) {
filter.append (SENDER_IDS + "." + entry.getKey (), entry.getValue ());
}
final Partnership inverseResult = partnerships.find (filter)
.map (MongoDBPartnershipFactory::toPartnership)
.first ();
if (inverseResult != null) {
result = new Partnership (inverseResult.getName () + "-inverse");
result.setReceiverX509Alias (inverseResult.getSenderX509Alias ());
result.setReceiverAS2ID (inverseResult.getSenderAS2ID ());
result.setSenderX509Alias (inverseResult.getReceiverX509Alias ());
result.setSenderAS2ID (inverseResult.getReceiverAS2ID ());
return result;
}
return null;
}
@Override
public Partnership getPartnershipByName (final String sName) {
return partnerships.find (new Document (NAME_KEY, sName)).map (MongoDBPartnershipFactory::toPartnership).first ();
}
@Override
public ICommonsSet <String> getAllPartnershipNames () {
return partnerships.distinct (NAME_KEY, String.class).into (new CommonsHashSet<> ());
}
@Override
public ICommonsList <Partnership> getAllPartnerships () {
return partnerships.find ().map (MongoDBPartnershipFactory::toPartnership).into (new CommonsArrayList<> ());
}
private static Document toDocument (final IStringMap stringMap) {
final Document document = new Document ();
for (final Entry <String, String> entry : stringMap) {
document.put (entry.getKey (), entry.getValue ());
}
return document;
}
private static Document toDocument (final Partnership partnership) {
final Document document = new Document ();
document.put (NAME_KEY, partnership.getName ());
document.put (RECEIVER_IDS, toDocument (partnership.getAllReceiverIDs ()));
document.put (SENDER_IDS, toDocument (partnership.getAllSenderIDs ()));
document.put (ATTRIBUTES, toDocument (partnership.getAllAttributes ()));
return document;
}
private static Partnership toPartnership (final Document document) {
final Partnership partnership = new Partnership (document.getString (NAME_KEY));
final Document senderIDs = (Document) document.get (SENDER_IDS);
final ICommonsMap <String, String> senders = new CommonsHashMap<> (senderIDs.size ());
for (final Entry <String, Object> e : senderIDs.entrySet ()) {
senders.put (e.getKey (), e.getValue ().toString ());
}
partnership.addSenderIDs (senders);
final Document receiverIDs = (Document) document.get (RECEIVER_IDS);
final ICommonsMap <String, String> receivers = new CommonsHashMap<> (receiverIDs.size ());
for (final Entry <String, Object> e : receiverIDs.entrySet ()) {
receivers.put (e.getKey (), e.getValue ().toString ());
}
partnership.addReceiverIDs (receivers);
final Document attributes = (Document) document.get (ATTRIBUTES);
if (attributes != null) {
final ICommonsMap <String, String> att = new CommonsHashMap<> (receiverIDs.size ());
for (final Entry <String, Object> e : attributes.entrySet ()) {
att.put (e.getKey (), e.getValue ().toString ());
}
partnership.addAllAttributes (att);
}
return partnership;
}
}