package won.node.facet.impl;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.StmtIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import won.protocol.exception.*;
import won.protocol.message.WonMessage;
import won.protocol.model.Connection;
import won.protocol.model.ConnectionState;
import won.protocol.model.FacetType;
import won.protocol.repository.ConnectionRepository;
import won.protocol.vocabulary.WON;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* User: Danijel
* Date: 9.12.13.
* Time: 19.20
* To change this template use File | Settings | File Templates.
*/
public class CoordinatorFacetImpl extends AbstractFacet
{
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ConnectionRepository connectionRepository;
@Override
public FacetType getFacetType() {
return FacetType.CoordinatorFacet;
}
@Override
public void connectFromOwner(final Connection con, final Model content, final WonMessage wonMessage)
throws NoSuchNeedException, IllegalMessageForNeedStateException, ConnectionAlreadyExistsException {
logger.debug("Coordinator: ConntectFromOwner");
Resource baseRes = content.getResource(content.getNsPrefixURI(""));
StmtIterator stmtIterator = baseRes.listProperties(WON.HAS_REMOTE_FACET);
if (!stmtIterator.hasNext())
throw new IllegalArgumentException("at least one RDF node must be of type won:hasRemoteFacet");
//TODO: This should just remove RemoteFacet from content and replace the value of Facet with the one from RemoteFacet
final Model remoteFacetModel = ModelFactory.createDefaultModel();
remoteFacetModel.setNsPrefix("", "no:uri");
baseRes = remoteFacetModel.createResource(remoteFacetModel.getNsPrefixURI(""));
Resource remoteFacetResource = stmtIterator.next().getObject().asResource();
baseRes.addProperty(WON.HAS_FACET, remoteFacetModel.createResource(remoteFacetResource.getURI()));
final Connection connectionForRunnable = con;
// try {
// final ListenableFuture<URI> remoteConnectionURI = needProtocolNeedService.connect(con.getRemoteNeedURI(),
// con.getNeedURI(), connectionForRunnable.getConnectionURI(), remoteFacetModel, wonMessage);
// this.executorService.execute(new Runnable(){
// @Override
// public void run() {
// try{
// if (logger.isDebugEnabled()) {
// logger.debug("saving remote connection URI");
// }
// dataService.updateRemoteConnectionURI(con, remoteConnectionURI.get());
// } catch (Exception e) {
// logger.warn("Error saving connection {}. Stacktrace follows", con);
// logger.warn("Error saving connection ", e);
// }
// }
// });
// } catch (WonProtocolException e) {
// // we can't connect the connection. we send a close back to the owner
// // TODO should we introduce a new protocol method connectionFailed (because it's not an owner deny but some protocol-level error)?
// // For now, we call the close method as if it had been called from the remote side
// // TODO: even with this workaround, it would be good to send a content along with the close (so we can explain what happened).
//// try {
//// Connection c = closeConnectionLocally(connectionForRunnable, content);
//// // ToDo (FS): should probably not be the same wonMessage!?
//// needFacingConnectionCommunicationService.close(c.getConnectionURI(), content, wonMessage);
//// } catch (NoSuchConnectionException e1) {
//// logger.warn("caught NoSuchConnectionException:", e1);
//// } catch (IllegalMessageForConnectionStateException e1) {
//// logger.warn("caught IllegalMessageForConnectionStateException:", e1);
//// }
// }
// catch (InterruptedException e) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
// } catch (ExecutionException e) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
// } catch (Exception e) {
// logger.debug("caught Exception", e);
// }
}
public void openFromOwner(final Connection con, final Model content, final WonMessage wonMessage)
throws NoSuchConnectionException, IllegalMessageForConnectionStateException {
//inform the other side
logger.debug("Coordinator: OpenFromOwner");
if (con.getRemoteConnectionURI() != null) {
// executorService.execute(new Runnable() {
// @Override
// public void run() {
// try {
// needFacingConnectionClient.open(con, content, wonMessage);
// } catch (WonProtocolException e) {
// logger.debug("caught Exception:", e);
// } catch (Exception e) {
// logger.debug("caught Exception", e);
// }
// }
// });
}
}
public void openFromNeed(final Connection con, final Model content, final WonMessage wonMessage)
throws NoSuchConnectionException, IllegalMessageForConnectionStateException {
//inform the need side
logger.debug("Coordinator: OpenFromNeed");
executorService.execute(new Runnable()
{
@Override
public void run()
{
// try {
// ownerFacingConnectionClient.open(con.getConnectionURI(), content);
List<Connection> cons = connectionRepository.findByNeedURIAndStateAndTypeURI(con.getNeedURI(),
ConnectionState.REQUEST_SENT, FacetType.CoordinatorFacet.getURI());
boolean fAllVotesReceived = cons.isEmpty();
if(fAllVotesReceived){
Model myContent = ModelFactory.createDefaultModel();
myContent.setNsPrefix("","no:uri");
Resource baseResource = myContent.createResource("no:uri");
baseResource.addProperty(WON_TX.COORDINATION_MESSAGE, WON_TX.COORDINATION_MESSAGE_COMMIT);
//TODO: use new system
//ownerFacingConnectionClient.open(con.getConnectionURI(), myContent, wonMessage);
globalCommit(con);
}
else{
logger.debug("Wait for votes of: ");
for(Connection c : cons)
{
logger.debug(" " + c.getConnectionURI() + " " + c.getNeedURI() + " " + c.getRemoteNeedURI());
}
//TODO: use new system
//ownerFacingConnectionClient.open(con.getConnectionURI(), content, wonMessage);
}
// } catch (WonProtocolException e) {
// logger.debug("caught Exception:", e);
// }
}
});
}
@Override
public void closeFromNeed(final Connection con, final Model content, final WonMessage wonMessage)
throws NoSuchConnectionException, IllegalMessageForConnectionStateException {
//inform the need side
logger.debug("Coordinator: closeFromOwner");
executorService.execute(new Runnable()
{
@Override
public void run()
{
// try {
//TODO: use new system
//ownerFacingConnectionClient.close(con.getConnectionURI(), content, wonMessage);
globalAbort(con);
// } catch (WonProtocolException e) {
// logger.warn("caught WonProtocolException:", e);
// }
}
});
}
private void globalAbort(Connection con) {
Model myContent = ModelFactory.createDefaultModel();
myContent.setNsPrefix("","no:uri");
Resource baseResource = myContent.createResource("no:uri");
baseResource.addProperty(WON_TX.COORDINATION_MESSAGE, WON_TX.COORDINATION_MESSAGE_ABORT);
abortTransaction(con, myContent);
}
public void globalCommit(Connection con)
{
Model myContent = ModelFactory.createDefaultModel();
myContent.setNsPrefix("","no:uri");
Resource baseResource = myContent.createResource("no:uri");
baseResource.addProperty(WON_TX.COORDINATION_MESSAGE, WON_TX.COORDINATION_MESSAGE_COMMIT);
commitTransaction(con, myContent);
}
public void abortTransaction(Connection con, Model content)
{
List<Connection> cons = connectionRepository.findByNeedURI(con.getNeedURI());
try{
for(Connection c : cons)
{
if(c.getState()!=ConnectionState.CLOSED)
{
Model myContent = ModelFactory.createDefaultModel();
myContent.setNsPrefix("","no:uri");
Resource res = myContent.createResource("no:uri");
if(c.getState() == ConnectionState.CONNECTED || c.getState() == ConnectionState.REQUEST_SENT)
{
if (res == null) {
logger.debug("no default prexif specified in model, could not obtain additional content, using ABORTED message");
}
res.removeAll(WON_TX.COORDINATION_MESSAGE);
res.addProperty(WON_TX.COORDINATION_MESSAGE, WON_TX.COORDINATION_MESSAGE_ABORT);
}
//todo: use new system
//closeConnectionLocally(c, content);
//needFacingConnectionClient.close(c, myContent, null); //Abort sent to participant
}
}
// } catch (WonProtocolException e) {
// logger.warn("caught WonProtocolException:", e);
} catch (Exception e) {
logger.debug("caught Exception", e);
}
}
public void commitTransaction(Connection con, Model content)
{
List<Connection> cons = connectionRepository.findByNeedURIAndStateAndTypeURI(con.getNeedURI(),
ConnectionState.CONNECTED, FacetType.CoordinatorFacet.getURI());
try{
for(Connection c : cons)
{
if(c.getState()==ConnectionState.CONNECTED)
{
//emulate a close by owner
//todo: use new system
//c = closeConnectionLocally(c, content);
//tell the partner
//needFacingConnectionClient.close(c, content, null);
}
}
logger.debug("Transaction commited!");
// } catch (WonProtocolException e) {
// logger.warn("caught WonProtocolException:", e);
} catch (Exception e) {
logger.debug("caught Exception",e);
}
}
}