diff options
Diffstat (limited to 'sandbox/dougsleite/implementation-guardian/src/main/java/org/apache/tuscany/sca/implementation/guardian/impl/GuardianGroupImpl.java')
-rw-r--r-- | sandbox/dougsleite/implementation-guardian/src/main/java/org/apache/tuscany/sca/implementation/guardian/impl/GuardianGroupImpl.java | 644 |
1 files changed, 644 insertions, 0 deletions
diff --git a/sandbox/dougsleite/implementation-guardian/src/main/java/org/apache/tuscany/sca/implementation/guardian/impl/GuardianGroupImpl.java b/sandbox/dougsleite/implementation-guardian/src/main/java/org/apache/tuscany/sca/implementation/guardian/impl/GuardianGroupImpl.java new file mode 100644 index 0000000000..5a243560e3 --- /dev/null +++ b/sandbox/dougsleite/implementation-guardian/src/main/java/org/apache/tuscany/sca/implementation/guardian/impl/GuardianGroupImpl.java @@ -0,0 +1,644 @@ +/* + * 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.implementation.guardian.impl; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import org.apache.axiom.om.OMAttribute; +import org.apache.axiom.om.OMElement; +import org.apache.tuscany.sca.contribution.service.ContributionReadException; +import org.apache.tuscany.sca.implementation.guardian.common.InvalidRegularExpressionException; +import org.apache.tuscany.sca.implementation.guardian.GuardianGroup; +import org.apache.tuscany.sca.implementation.guardian.GuardianMember; +import org.apache.tuscany.sca.implementation.guardian.common.ConcurrentExceptionOcurrenceException; +import org.apache.tuscany.sca.implementation.guardian.common.Constants; +import org.apache.tuscany.sca.implementation.guardian.common.Context; +import org.apache.tuscany.sca.implementation.guardian.common.GlobalException; +import org.apache.tuscany.sca.implementation.guardian.common.GlobalExceptionInterface; +import org.apache.tuscany.sca.implementation.guardian.common.InvalidNodeException; +import org.apache.tuscany.sca.implementation.guardian.common.ResolutionTreeUtils; +import org.apache.tuscany.sca.implementation.guardian.common.SuspendException; +import org.apache.tuscany.sca.implementation.guardian.xml.RecoveryRulesProcessor; +import org.apache.tuscany.sca.implementation.guardian.xml.ResolutionTreesProcessor; + +public class GuardianGroupImpl implements GuardianGroup { + + private List<GuardianMember> guardianList; + private InnerGuardianGroupThread innerThread; + private List<GlobalExceptionInterface> concurrentExList; + private Map<String, OMElement> resolutionTreeElements; + private ResolutionTreeUtils resolutionTreeUtils; + private Map<String, OMElement> ruleElements; + + public GuardianGroupImpl(String recoveryRules, String resolutionTrees) { + guardianList = new LinkedList<GuardianMember>(); + concurrentExList = new LinkedList<GlobalExceptionInterface>(); + innerThread = new InnerGuardianGroupThread(); + resolutionTreeUtils = new ResolutionTreeUtils(); + + setRecoveryRules(recoveryRules); + setResolutionTree(resolutionTrees); + } + + private void setRecoveryRules(String recoveryRules) { + try { + FileInputStream fileInputStream = new FileInputStream(recoveryRules); + XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(fileInputStream); + + RecoveryRulesProcessor processor = new RecoveryRulesProcessor(); + ruleElements = processor.read(xmlReader).getRuleElements(); + + } catch (ContributionReadException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } catch (XMLStreamException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } catch (FileNotFoundException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private void setResolutionTree(String resolutionTree) { + + try { + FileInputStream fileInputStream = new FileInputStream(resolutionTree); + XMLStreamReader resolutionTreeReader = XMLInputFactory.newInstance().createXMLStreamReader(fileInputStream); + + ResolutionTreesProcessor processor = new ResolutionTreesProcessor(); + resolutionTreeElements = processor.read(resolutionTreeReader).getResolutionTreeElements(); + + } catch (ContributionReadException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } catch (XMLStreamException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } catch (FileNotFoundException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public void addGuardianMember(GuardianMember guardianMember) { + guardianList.add(guardianMember); + guardianMember.setUniqueParticipantID(guardianList.size() - 1); + } + + public boolean removeGuardianMember(GuardianMember guardianMember) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void enableContext(Context context) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void removeContext() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public synchronized void gthrow(GlobalExceptionInterface ex, List<String> participantList) { + + concurrentExList.add(ex); + + //Sends a message representing the exception to the other guardian members + SuspendException suspendEx = new SuspendException(); + suspendEx.putSignalingParticipant(ex.getSignalingParticipants().get(0)); + + if (participantList == null) { + for (GuardianMember g : guardianList) { + g.gthrow(suspendEx, null); + } + } else { + for (GuardianMember g : guardianList) { + if (participantList.contains(g.getParticipantIdentifier()) || + g.getParticipantIdentifier().equals(ex.getSignalingParticipants().get(0))) { + g.gthrow(suspendEx, null); + } + } + } + + if (!innerThread.isRunning()) { + innerThread.setGlobalException(ex); + new Thread(innerThread).start(); + } + + } + + public boolean propagate(GlobalExceptionInterface ex) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void checkExceptionStatus() { + throw new UnsupportedOperationException("Not supported yet."); + } + + private class InnerGuardianGroupThread implements Runnable { + + private boolean isRunning; + private GlobalExceptionInterface ex = null; + + public InnerGuardianGroupThread() { + isRunning = false; + } + + public void setGlobalException(GlobalExceptionInterface ex) { + this.ex = ex; + } + + public GlobalExceptionInterface getGlobalException() { + return ex; + } + + public void run() { + isRunning = true; + + if (ex != null) { + + //Time window of 10 seconds just for tests + try { + Thread.sleep(10000); + } catch (InterruptedException ex1) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex1); + } + + try { + applyRecoveryRules(ex); + } catch (ConcurrentExceptionOcurrenceException ce) { + applyConcurrentRecoveryRules(); + } + + //Clear the concurrent exception list + concurrentExList.clear(); + + //Set up the participant state to NORMAL + for (GuardianMember gm : guardianList) { + if (gm.getParticipantState() == SUSPENDED_PARTICIPANT_STATE) { + gm.setParticipantState(NORMAL_PARTICIPANT_STATE); + } + } + } + isRunning = false; + } + + public boolean isRunning() { + return isRunning; + } + + private void applyRecoveryRules(GlobalExceptionInterface ex) throws ConcurrentExceptionOcurrenceException { + ruleTag(ex, ruleElements.values().iterator()); + } + + private void ruleTag(GlobalExceptionInterface ex, Iterator<OMElement> ruleElements) throws ConcurrentExceptionOcurrenceException { + String signaledException; + String exceptionName; + + OMElement rule; + while (ruleElements.hasNext()) { + + rule = ruleElements.next(); + signaledException = getAttributeValue(rule, Constants.SIGNALED_EXCEPTION); + exceptionName = ex.getClass().getName(); + + if (signaledException.equals(exceptionName)) { + participantExceptionTag(ex, rule.getChildElements()); + break; + } + } + } + + private void participantExceptionTag(GlobalExceptionInterface ex, Iterator<OMElement> participantElements) throws ConcurrentExceptionOcurrenceException { + String matchParticipant; + List<GuardianMember> gmList; + + OMElement participant; + while (participantElements.hasNext()) { + participant = participantElements.next(); + + matchParticipant = getAttributeValue(participant, Constants.MATCH); + gmList = getMatchingParticipants(matchParticipant, ex); + + if (!gmList.isEmpty()) { + throwExceptionTag(gmList, ex, participant.getChildElements()); + } + } + } + + private void throwExceptionTag(List<GuardianMember> gmList, GlobalExceptionInterface ex, Iterator<OMElement> throwExceptionElements) throws ConcurrentExceptionOcurrenceException { + String className; + String targetContextName; + Integer minParticipantJoined; + Integer maxParticipantJoined; + + OMElement throwException; + while (throwExceptionElements.hasNext()) { + + throwException = throwExceptionElements.next(); + + className = getAttributeValue(throwException, Constants.CLASS); + targetContextName = getAttributeValue(throwException, Constants.TARGET_CONTEXT); + + try { + minParticipantJoined = Integer.parseInt(getAttributeValue(throwException, Constants.MIN_PARTICIPANT_JOINED)); + } catch (NumberFormatException nex) { + minParticipantJoined = null; + } + + try { + maxParticipantJoined = Integer.parseInt(getAttributeValue(throwException, Constants.MAX_PARTICIPANT_JOINED)); + } catch (NumberFormatException nexc) { + maxParticipantJoined = null; + } + + //Test the min and max joined participants condition + if (minParticipantJoined != null && maxParticipantJoined != null) { + if (!(guardianList.size() >= minParticipantJoined && guardianList.size() < maxParticipantJoined)) { + break; + } + } else if (minParticipantJoined != null) { + if (!(guardianList.size() >= minParticipantJoined)) { + break; + } + } else if (minParticipantJoined != null) { + if (!(guardianList.size() >= minParticipantJoined)) { + break; + } + } + + //<affected_participants> + String affectedParticipants = affectedParticipantsTag(throwException.getChildElements()); + int index = -1; + + //Verify if the parameter is an index + try { + index = Integer.parseInt(affectedParticipants); + } catch (NumberFormatException nexc) { + index = -1; + } + + //Create the new exception instance + Class exceptionClass; + try { + exceptionClass = Class.forName(className); + + Context targetContext; + if (targetContextName.toUpperCase().equals(Context.CURRENT_CONTEXT.getName().toUpperCase())) { + targetContext = Context.CURRENT_CONTEXT; + } else if (targetContextName.toUpperCase().equals(Context.INIT_CONTEXT.getName().toUpperCase())) { + targetContext = Context.INIT_CONTEXT; + } else { + targetContext = new Context(targetContextName); + } + GlobalException newException = (GlobalException) exceptionClass.newInstance(); + + newException.setTargetContext(targetContext); + newException.setSignalingContext(ex.getSignalingContext()); + newException.putSignalingParticipant(ex.getSignalingParticipants().toString()); + + //Check concurrent exception existence + if (concurrentExList.size() > 1) { + throw new ConcurrentExceptionOcurrenceException(concurrentExList.toString()); + } + + //Add the exception to the participants matched + if (index != -1) { + gmList.get(index).addException(newException); + } else if (affectedParticipants != null && affectedParticipants.length() != 0) { + if (affectedParticipants.toUpperCase().equals(Constants.FIRST)) { + gmList.get(0).addException(newException); + } else if (affectedParticipants.toUpperCase().equals(Constants.LAST)) { + gmList.get(gmList.size() - 1).addException(newException); + } else if (affectedParticipants.toUpperCase().equals(Constants.ALL)) { + for (GuardianMember gm : gmList) { + gm.addException(newException); + } + } + } else { + for (GuardianMember gm : gmList) { + gm.addException(newException); + } + } + + } catch (InstantiationException ex1) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex1); + } catch (IllegalAccessException ex1) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex1); + } catch (ClassNotFoundException ex1) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex1); + } + } + } + + private String affectedParticipantsTag(Iterator<OMElement> affectedParticipantElements) { + + String affectedParticipantValue = null; + + OMElement affectedParticipant; + while (affectedParticipantElements.hasNext()) { + + affectedParticipant = affectedParticipantElements.next(); + affectedParticipantValue = affectedParticipant.getText(); + } + + if (affectedParticipantValue != null && affectedParticipantValue.length() == 0) { + affectedParticipantValue = null; + } + + return affectedParticipantValue; + } + + private String getAttributeValue(OMElement element, String attributeName) { + OMAttribute at; + Iterator it = element.getAllAttributes(); + + while (it.hasNext()) { + at = (OMAttribute) it.next(); + if (at.getLocalName().equals(attributeName)) { + return at.getAttributeValue(); + } + } + + return null; + } + + private void applyConcurrentRecoveryRules() { + + boolean concurrentExOcurrence = false; + List<GlobalExceptionInterface> copyConcurrentExList; + GlobalExceptionInterface resolvedEx; + + do { + System.out.println("Concurrent exceptions: " + concurrentExList); + + copyConcurrentExList = new LinkedList(concurrentExList); + + resolvedEx = checkExceptionResolutionTrees(copyConcurrentExList, resolutionTreeElements.values().iterator()); + + concurrentExList.clear(); + + System.out.println("Resolved Exception: " + resolvedEx); + if (resolvedEx != null) { + System.out.println("List of participants: " + resolvedEx.getSignalingParticipants()); + } + + try { + //Process the exception list sequentially + if (resolvedEx == null) { + for (GlobalExceptionInterface ex : copyConcurrentExList) { + applyRecoveryRules(ex); + } + } else { + applyRecoveryRules(resolvedEx); + } + + } catch (ConcurrentExceptionOcurrenceException exc) { + concurrentExOcurrence = true; + break; + } + } while (concurrentExOcurrence); + } + + //FIXME: Need to check the exception level + private GlobalExceptionInterface checkExceptionResolutionTrees(List<GlobalExceptionInterface> exceptionList, Iterator resolutionTreesElements) { + + OMElement tree; + OMElement root; + String exceptionLevel = null; + GlobalExceptionInterface resolvedEx = null; + + while (resolutionTreesElements.hasNext()) { + tree = (OMElement) resolutionTreesElements.next(); + exceptionLevel = tree.getAttributeValue(Constants.EXCEPTION_LEVEL_QNAME); + + root = (OMElement) tree.getChildElements().next(); + resolvedEx = checkExceptionResolutionTree(exceptionList, root); + + if (resolvedEx != null) { + break; + } + } + + return resolvedEx; + } + + //Search for the root of the smallest subtree that contains all the concurrently signaled exceptions. If not found, return null. + private GlobalExceptionInterface checkExceptionResolutionTree(List<GlobalExceptionInterface> exceptionList, OMElement rootTree) { + + resolutionTreeUtils.setRoot(rootTree); + String ex1, ex2; + GlobalExceptionInterface resolvedEx = null; + + ex1 = exceptionList.get(0).getClass().getName(); + for (int i = 1; i < exceptionList.size(); i++) { + ex2 = exceptionList.get(i).getClass().getName(); + + try { + ex1 = resolutionTreeUtils.getLowestCommonAncestor(ex1, ex2); + } catch (InvalidNodeException invalidNodeException) { + ex1 = null; + break; + } + } + + if (ex1 != null) { + Class exceptionClass; + + try { + exceptionClass = Class.forName(ex1); + resolvedEx = (GlobalException) exceptionClass.newInstance(); + + for (GlobalExceptionInterface ex : exceptionList) { + resolvedEx.putSignalingParticipant(ex.getSignalingParticipants().get(0)); + } + + } catch (InstantiationException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotFoundException ex) { + Logger.getLogger(GuardianGroupImpl.class.getName()).log(Level.SEVERE, null, ex); + } + + return resolvedEx; + + } else { + return null; + } + } + + private List<GuardianMember> getMatchingParticipants(String regularExpression, GlobalExceptionInterface signaledException) { + List<GuardianMember> matchingParticipants = new LinkedList(); + String[] splitByComma = regularExpression.split(","); + + //Invalid regular expression + if (splitByComma.length > 2) { + throw new InvalidRegularExpressionException("The comma ',' operator can only be applied for two expressions"); + } + + //There is no comma on the regular expression + if (splitByComma.length == 1) { + + if (regularExpression.toUpperCase().equals("SIGNALER")) { + for (GuardianMember gm : guardianList) { + if (signaledException.getSignalingParticipants().contains(gm.getParticipantIdentifier())) { + matchingParticipants.add(gm); + } + } + } else if (regularExpression.toUpperCase().equals("!SIGNALER")) { + for (GuardianMember gm : guardianList) { + if (!signaledException.getSignalingParticipants().contains(gm.getParticipantIdentifier())) { + matchingParticipants.add(gm); + } + } + + } else { + //Create an java regular expression + String re = createJavaRegularExpression(regularExpression); + + for (GuardianMember gm : guardianList) { + if (gm.getParticipantIdentifier().matches(re)) { + matchingParticipants.add(gm); + } + } + } + + } //There is comma on the regular expression + else { + + String element; + int index = -1; + for (int i = 0; i < splitByComma.length; i++) { + element = splitByComma[i].toUpperCase(); + if (element.equals("SIGNALER") || element.equals("!SIGNALER")) { + if (index == -1) { + index = i; + } else { + index = -1; + } + } + } + + //Invalid expression + if (index == -1) { + throw new InvalidRegularExpressionException("The comma ',' requires a SIGNALER or !SIGNALER element in one side of the expression"); + } + + String re = createJavaRegularExpression(splitByComma[1 - index]); + + for (GuardianMember gm : guardianList) { + + //Test if the participant matches with the regular expression + if (gm.getParticipantIdentifier().matches(re)) { + + //Test if the participant is Signaler + if (splitByComma[index].toUpperCase().equals("SIGNALER")) { + + if (signaledException.getSignalingParticipants().contains(gm.getParticipantIdentifier())) { + matchingParticipants.add(gm); + } + } //Test if the participant is not Signaler + else { + if (!signaledException.getSignalingParticipants().contains(gm.getParticipantIdentifier())) { + matchingParticipants.add(gm); + } + } + } + } + + } + + return matchingParticipants; + } + + /* Valid expressions: *, <Context>.*, <Context>, *.<Context>, *.<Context>.*, + * *.<Context>.*.<Context>.*, <REG_EXP> || <REG_EXP> + * + * Invalid expressions: *.*, **, + * + * Not supported yet: !<Context>, !<Context> || <Context>, !(<Context> || <Context>) + */ + private String createJavaRegularExpression(String regularExpression) throws InvalidRegularExpressionException { + StringBuffer re = new StringBuffer(); + + String[] splitByBar = regularExpression.split("\\|\\|"); + String[] splitByPeriod; + + for (int i = 0; i < splitByBar.length; i++) { + + splitByPeriod = splitByBar[i].split("\\."); + + if (i > 0) { + re.append("|"); + } + + re.append("^"); + for (int j = 0; j < splitByPeriod.length; j++) { + + //* + if (splitByPeriod[j].equals("*")) { + + //Validate the regular expression + if (j + 1 != splitByPeriod.length && splitByPeriod[j + 1].equals("*")) { + throw new InvalidRegularExpressionException(); + } + + //* + if (splitByPeriod.length == 1) { + re.append("(\\w+)"); + } //*.<CONTEXT> + + if (j == 0 && splitByPeriod.length != 1) { + re.append("(\\w+\\"); + re.append(".)*"); + } //<CONTEXT>.* + else { + re.append("(\\"); + re.append(".\\w+)*"); + } + } //<CONTEXT> + else { + +// //Validate the regular expression +// if (splitedByPeriod[j].matches("^(\\*)*$")) { +// throw new RuntimeException("Invalid name for a context"); +// } + + //<CONTEXT> || <CONTEXT>.<CONTEXT>.<CONTEXT> || *.<CONTEXT> + if (splitByPeriod.length == 1) { + re.append("(\\w+\\"); + re.append(".)*"); + } + + if (j == 0 || j - 1 == 0) { + re.append("(" + splitByPeriod[j] + ")"); + } else { + re.append("(\\." + splitByPeriod[j] + ")"); + } + } + } + re.append("$"); + } + return re.toString(); + } + } +} |