package won.node.camel.processor.fixed;
import org.apache.jena.query.Dataset;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.javasimon.SimonManager;
import org.javasimon.Split;
import org.javasimon.Stopwatch;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import won.node.camel.processor.AbstractCamelProcessor;
import won.node.camel.processor.annotation.FixedMessageProcessor;
import won.protocol.message.WonMessage;
import won.protocol.message.processor.camel.WonCamelConstants;
import won.protocol.message.processor.exception.UriAlreadyInUseException;
import won.protocol.model.*;
import won.protocol.util.NeedModelWrapper;
import won.protocol.util.WonRdfUtils;
import won.protocol.vocabulary.WONMSG;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* User: syim
* Date: 02.03.2015
*/
@Service
@FixedMessageProcessor(direction= WONMSG.TYPE_FROM_OWNER_STRING,messageType = WONMSG.TYPE_CREATE_STRING)
public class CreateNeedMessageProcessor extends AbstractCamelProcessor
{
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public void process(final Exchange exchange) throws Exception {
Message message = exchange.getIn();
WonMessage wonMessage = (WonMessage) message.getHeader(WonCamelConstants.MESSAGE_HEADER);
Need need = storeNeed(wonMessage);
authorizeOwnerApplicationForNeed(message, need);
}
private Need storeNeed(final WonMessage wonMessage) {
Dataset needContent = wonMessage.getMessageContent();
List<WonMessage.AttachmentHolder> attachmentHolders = wonMessage.getAttachments();
//remove attachment and its signature from the needContent
removeAttachmentsFromNeedContent(needContent, attachmentHolders);
URI needURI = getNeedURIFromWonMessage(needContent);
if (!needURI.equals(wonMessage.getSenderNeedURI()))
throw new IllegalArgumentException("receiverNeedURI and NeedURI of the content are not equal");
Need need = new Need();
need.setState(NeedState.ACTIVE);
need.setNeedURI(needURI);
// ToDo (FS) check if the WON node URI corresponds with the WON node (maybe earlier in the message layer)
NeedEventContainer needEventContainer = needEventContainerRepository.findOneByParentUri(needURI);
if (needEventContainer == null) {
needEventContainer = new NeedEventContainer(need, need.getNeedURI());
} else {
throw new UriAlreadyInUseException("Found a NeedEventContainer for the need we're about to create (" + needURI + ") - aborting");
}
needEventContainer.getEvents().add(messageEventRepository.findOneByMessageURI(wonMessage.getMessageURI()));
need.setWonNodeURI(wonMessage.getReceiverNodeURI());
ConnectionContainer connectionContainer = new ConnectionContainer(need);
need.setConnectionContainer(connectionContainer);
need.setEventContainer(needEventContainer);
//store the need content
DatasetHolder datasetHolder = new DatasetHolder(needURI, needContent);
//store attachments
List<DatasetHolder> attachments = new ArrayList<>(attachmentHolders.size());
for(WonMessage.AttachmentHolder attachmentHolder: attachmentHolders){
datasetHolder = new DatasetHolder(attachmentHolder.getDestinationUri(), attachmentHolder.getAttachmentDataset());
attachments.add(datasetHolder);
}
//add everything to the need model class and save it
need.setDatatsetHolder(datasetHolder);
need.setAttachmentDatasetHolders(attachments);
need = needRepository.save(need);
connectionContainerRepository.save(connectionContainer);
NeedModelWrapper needModelWrapper = new NeedModelWrapper(needContent);
Collection<String> facets = needModelWrapper.getFacetUris();
if (facets.size() == 0)
throw new IllegalArgumentException("at least one property won:hasFacet required ");
for (String facetUri : facets) {
// TODO: check if there is a implementation for the facet on the node
Facet f = new Facet();
f.setNeedURI(needURI);
f.setTypeURI(URI.create(facetUri));
facetRepository.save(f);
}
return need;
}
private void removeAttachmentsFromNeedContent(Dataset needContent, List<WonMessage.AttachmentHolder> attachmentHolders) {
for (WonMessage.AttachmentHolder attachmentHolder: attachmentHolders){
for (Iterator<String> it = attachmentHolder.getAttachmentDataset().listNames(); it.hasNext(); ){
String modelName =it.next();
needContent.removeNamedModel(modelName);
}
}
}
private void authorizeOwnerApplicationForNeed(final Message message, final Need need) {
String ownerApplicationID = message.getHeader(WonCamelConstants.OWNER_APPLICATION_ID).toString();
authorizeOwnerApplicationForNeed(ownerApplicationID, need);
}
private URI getNeedURIFromWonMessage(final Dataset wonMessage) {
URI needURI;
needURI = WonRdfUtils.NeedUtils.getNeedURI(wonMessage);
if (needURI == null) {
throw new IllegalArgumentException("at least one RDF node must be of type won:Need");
}
return needURI;
}
private void authorizeOwnerApplicationForNeed(final String ownerApplicationID, Need need) {
String stopwatchName = getClass().getName() + ".authorizeOwnerApplicationForNeed";
Stopwatch stopwatch = SimonManager.getStopwatch(stopwatchName + "_phase1");
Split split = stopwatch.start();
List<OwnerApplication> ownerApplications = ownerApplicationRepository.findByOwnerApplicationId(ownerApplicationID);
split.stop();
stopwatch = SimonManager.getStopwatch(stopwatchName + "_phase2");
split = stopwatch.start();
if (ownerApplications.size() > 0) {
logger.debug("owner application is already known");
OwnerApplication ownerApplication = ownerApplications.get(0);
List<OwnerApplication> authorizedApplications = need.getAuthorizedApplications();
if (authorizedApplications == null) {
authorizedApplications = new ArrayList<OwnerApplication>(1);
}
authorizedApplications.add(ownerApplication);
need.setAuthorizedApplications(authorizedApplications);
} else {
logger.debug("owner application is new - creating");
List<OwnerApplication> ownerApplicationList = new ArrayList<>(1);
OwnerApplication ownerApplication = new OwnerApplication();
ownerApplication.setOwnerApplicationId(ownerApplicationID);
ownerApplicationList.add(ownerApplication);
need.setAuthorizedApplications(ownerApplicationList);
logger.debug("setting OwnerApp ID: " + ownerApplicationList.get(0));
}
split.stop();
stopwatch = SimonManager.getStopwatch(stopwatchName + "_phase3");
split = stopwatch.start();
need = needRepository.save(need);
split.stop();
}
}