/* * Copyright 2012 Research Studios Austria Forschungsges.m.b.H. * * 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 won.node.camel.processor.general; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import won.node.service.DataAccessService; import won.protocol.message.WonMessage; import won.protocol.message.WonMessageEncoder; import won.protocol.message.WonMessageType; import won.protocol.message.WonMessageUtils; import won.protocol.message.processor.WonMessageProcessor; import won.protocol.message.processor.exception.WonMessageProcessingException; import won.protocol.model.*; import won.protocol.repository.ConnectionEventContainerRepository; import won.protocol.repository.DatasetHolderRepository; import won.protocol.repository.MessageEventRepository; import won.protocol.repository.NeedEventContainerRepository; import java.net.URI; /** * Persists the specified WonMessage. */ public class PersistingWonMessageProcessor implements WonMessageProcessor { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired protected MessageEventRepository messageEventRepository; @Autowired protected ConnectionEventContainerRepository connectionEventContainerRepository; @Autowired protected NeedEventContainerRepository needEventContainerRepository; @Autowired protected DatasetHolderRepository datasetHolderRepository; @Autowired DataAccessService dataAccessService; @Override //we use READ_COMMITTED because we want to wait for an exclusive lock will accept data written by a concurrent transaction that commits before we read @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) public WonMessage process(WonMessage message) throws WonMessageProcessingException { URI parentURI = WonMessageUtils.getParentEntityUri(message); updateResponseInfo(message); saveMessage(message, parentURI); return message; } /** * If we are saving response message, update original massage with the * information about response message uri * @param message response message */ private void updateResponseInfo(final WonMessage message) { // find a message it responds to URI originalMessageURI = message.getIsResponseToMessageURI(); if (originalMessageURI != null) { // update the message it responds to with the uri of the response MessageEventPlaceholder event = messageEventRepository.findOneByMessageURIforUpdate(originalMessageURI); if (event != null){ //we may not have saved the event yet if the current message is a FailureResponse //and the error causing the response happened before saving the original message. event.setResponseMessageURI(message.getMessageURI()); messageEventRepository.save(event); } } } private void saveMessage(final WonMessage wonMessage, URI parent) { logger.debug("STORING message with uri {} and parent uri", wonMessage.getMessageURI(), parent); EventContainer container = loadOrCreateEventContainer(wonMessage, parent); DatasetHolder datasetHolder = new DatasetHolder(wonMessage.getMessageURI(), WonMessageEncoder.encodeAsDataset (wonMessage)); MessageEventPlaceholder event = new MessageEventPlaceholder(parent, wonMessage, container); event.setDatasetHolder(datasetHolder); messageEventRepository.save(event); //FIXLOSTUPDATES: //this could be part of the problem if the transaction stays open for a long time //options: // * commit immediately here (trying with REQURES_NEW) } private EventContainer loadOrCreateEventContainer(final WonMessage wonMessage, final URI parent) { WonMessageType type = wonMessage.getMessageType(); if (WonMessageType.CREATE_NEED.equals(type)) { //create a need event container with null parent (because it will only be persisted at a later point in time) EventContainer container = needEventContainerRepository.findOneByParentUriForUpdate(parent); if (container != null) return container; NeedEventContainer nec = new NeedEventContainer (null, parent); needEventContainerRepository.saveAndFlush(nec); return nec; } else if (WonMessageType.CONNECT.equals(type) || WonMessageType.HINT_MESSAGE.equals(type)) { //create a connection event container witn null parent (because it will only be persisted at a later point in // time) EventContainer container = connectionEventContainerRepository.findOneByParentUriForUpdate(parent); if (container != null) return container; ConnectionEventContainer cec = new ConnectionEventContainer(null, parent); connectionEventContainerRepository.saveAndFlush(cec); return cec; } EventContainer container = needEventContainerRepository.findOneByParentUriForUpdate(parent); if (container != null) return container; container = connectionEventContainerRepository.findOneByParentUriForUpdate(parent); if (container != null) return container; //let's see if we can find the event conta throw new IllegalArgumentException( "Cannot store '" + type + "' event '" + wonMessage.getMessageURI() + "': unable to find " + "event container with parent URI '" + parent + "'"); } }