/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.tuscany.sca.guardian; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import org.osoa.sca.annotations.Init; import org.osoa.sca.annotations.Reference; import org.osoa.sca.annotations.Scope; import org.osoa.sca.annotations.Destroy; @Scope("COMPOSITE") public class GuardianMemberImpl implements GuardianMember { private Stack contextList; private BlockingInterface service; private Queue exceptionQueue; @Reference(name = "guardian_group", required = true) public GuardianGroup guardianGroup; private int id; public GuardianMemberImpl() { contextList = new Stack(); exceptionQueue = new LinkedList(); } @Init public void init() { guardianGroup.addGuardianMember(this); } @Destroy public void destroy() { guardianGroup.removeGuardianMember(this); } public void addException(GlobalException ex) { exceptionQueue.add(ex); } public void setService(BlockingInterface service) { this.service = service; } public Context getCurrentContext() { return contextList.peek(); } public BlockingInterface getService() { return service; } public void enableContext(Context context) { //Update the context list with the related set of exceptions contextList.push(context); if (contextList.size() == 1) { gthrow(new JoinException(), null); } } public void removeContext() { if (!contextList.isEmpty()) { contextList.pop(); } } //Adapt to allow a regular expression //If participantList is null then signal to ALL participants public void gthrow(GlobalException ex, List participantList) { //1)Block the participant until raise an exception if (!service.isBlocked()) { service.block(); if (ex != null) { //Set the exception's parameters ex.setSignalingContext(getCurrentContext()); ex.setSignalingParticipant(getParticipantIdentifier()); guardianGroup.gthrow(ex, participantList); } //if (participantList == null || !participantList.contains(getParticipantIdentifier())) { // if (getParticipantIdentifier().equals(ex.getSignalingParticipant())) { // //2A)Call the gthrow of the GuardianGroup - communicate with other guardian members // System.out.println("HERE AT " + getParticipantIdentifier()); // guardianGroup.gthrow(ex, participantList); // } } //*Is here the best place to receive such kind of msg? // //2B)When receive exception_msg from GuardianGroup do // if participant is not suspended then suspend it // if participant supports interrupts then // interrupt it, add SuspendException in the exception_queue, and invoke checkExceptionStatus // else invoke checkExceptionStatus periodically // //4)Once ALL required participants are SUSPENDED (suspended point), invoke the defined Recovery Rules // 4.1) recovery_rules < signaled exceptions + context_list of all participant > target context + exception to raise // 4.2) raise the resolved exception in each participant -> it goes to the exception_queue } public boolean propagate(GlobalException ex) { //1)Compares the current context with the exception's target context return !getCurrentContext().equals(ex.getTargetContext()); } public void checkExceptionStatus() throws GlobalException { //1)Chek the exception queue // 1.1) if exception_queue is empty then return // else if first element on the exception_queue is SuspendException then // the method blocks until the next exception is received. The method raises the first non-SuspendException in the queue GlobalException exc; if ((exc = exceptionQueue.peek()) == null) { System.out.println(getParticipantIdentifier() + "#No exception on exception queue"); return; } else { while ((exc = exceptionQueue.peek()) instanceof SuspendException) { try { Thread.sleep(5000); } catch (InterruptedException ex) { Logger.getLogger(GuardianMemberImpl.class.getName()).log(Level.SEVERE, null, ex); } exceptionQueue.poll(); } service.unblock(); // if (exc != null) { // System.out.println("\n" + getParticipantIdentifier() + "#"); // System.out.println("Exc: " + exc); // System.out.println("TargetContext: " + exc.getTargetContext().getName()); // System.out.println("Signaling Participant: " + exc.getSignalingParticipant()); // System.out.println("Current Context: " + getCurrentContext().getName()); // System.out.println("Equals: " + exc.getTargetContext().equals(getCurrentContext()) + "\n"); // } //FIX-ME: ex.targetContext() matches the participant id -> could use regular expressions //Eg. ex.targetContext(): Main and participant id: Init/Main/Backup -> should throw the exception String[] contexts = getParticipantIdentifier().split("\\."); if (exc != null) { for (int i = contexts.length - 1; i > 0; i--) { if (exc.getTargetContext().equals(new Context(contexts[i]))) { System.out.println(getParticipantIdentifier() + "#Returning an exception"); exceptionQueue.poll(); throw exc; } } } // if (exc != null && exc.getTargetContext().equals(getCurrentContext())) { // System.out.println(getParticipantIdentifier() + "#Returning an exception"); // exceptionQueue.poll(); // throw exc; // } return; } } public String getParticipantIdentifier() { //1) Return the participant identifier -> context list dot separated StringBuffer id = new StringBuffer(); id.append(this.id + "." + Context.INIT_CONTEXT.getName()); for (int i = 0; i < contextList.size(); i++) { id.append("." + contextList.get(i).getName()); // if (i + 1 != contextList.size()) { // id.append("."); // } } return id.toString(); } public void setUniqueParticipantID(int id) { this.id = id; } public void removeService() { this.service = null; } }