001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ha.framework.server;
023:
024: import java.util.ArrayList;
025: import java.util.List;
026: import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
027: import org.jboss.ha.framework.interfaces.DistributedReplicantManager.ReplicantListener;
028: import org.jboss.ha.framework.interfaces.HAPartition;
029: import java.io.Serializable;
030: import EDU.oswego.cs.dl.util.concurrent.Latch;
031:
032: /**
033: * This class is a holder and manager of replicants.
034: * It manages lists of replicated objects and changes the list as the HAPartition
035: * notifies it.
036: *
037: * @author bill@burkecentral.com
038: * @version $Revision: 57188 $
039: *
040: * <p><b>Revisions:</b><br>
041: * <p><b>2002/01/13: Bill Burke</b>
042: * <ol>
043: * <li>Initial revision
044: * </ol>
045: */
046: public class HATarget implements ReplicantListener {
047: public static final int DISABLE_INVOCATIONS = 0;
048: public static final int MAKE_INVOCATIONS_WAIT = 1;
049: public static final int ENABLE_INVOCATIONS = 2;
050:
051: protected String replicantName;
052: protected ArrayList replicants = new ArrayList();
053: protected HAPartition partition = null;
054: protected org.jboss.logging.Logger log;
055: protected int clusterViewId = 0;
056: protected Serializable target;
057: protected int allowInvocationsStatus = 0;
058: protected Latch latch = null;
059:
060: public HATarget(HAPartition partition, String replicantName,
061: Serializable target, int allowInvocations) throws Exception {
062: this .replicantName = replicantName;
063: this .target = target;
064: init();
065: setInvocationsAuthorization(allowInvocations);
066: updateHAPartition(partition);
067: }
068:
069: public void init() throws Exception {
070: this .log = org.jboss.logging.Logger.getLogger(this .getClass());
071: }
072:
073: public String toString() {
074: StringBuffer buffer = new StringBuffer(super .toString());
075: buffer.append('{');
076: buffer.append("replicantName=" + replicantName);
077: buffer.append("partition=" + partition.getPartitionName());
078: buffer.append("clusterViewId=" + clusterViewId);
079: buffer.append("allowInvocationsStatus="
080: + allowInvocationsStatus);
081: buffer.append("replicants=" + replicants);
082: buffer.append('}');
083: return buffer.toString();
084: }
085:
086: public long getCurrentViewId() {
087: return (long) clusterViewId;
088: }
089:
090: public void destroy() {
091: try {
092: this .cleanExistenceInCurrentHAPartition();
093:
094: // maybe some threads are blocked: we let them go here:
095: //
096: setInvocationsAuthorization(HATarget.DISABLE_INVOCATIONS);
097: } catch (Exception e) {
098: log.error("failed to destroy", e);
099: }
100: }
101:
102: // After this call, the HATarget can still be queried for view change, etc. but
103: // the local node is no more part of the cluster: temporary state
104: //
105: public void disable() {
106: try {
107: if (this .partition != null) {
108: log.debug("Disabled called on HATarget");
109: this .partition.getDistributedReplicantManager().remove(
110: this .replicantName);
111: }
112: } catch (Exception e) {
113: log.error("failed to disable", e);
114: }
115: }
116:
117: public ArrayList getReplicants() {
118: return replicants;
119: }
120:
121: public void updateHAPartition(HAPartition partition)
122: throws Exception {
123: cleanExistenceInCurrentHAPartition();
124:
125: this .partition = partition;
126: DistributedReplicantManager drm = partition
127: .getDistributedReplicantManager();
128: drm.registerListener(this .replicantName, this );
129: drm.add(this .replicantName, this .target);
130: }
131:
132: public synchronized void setInvocationsAuthorization(int status) {
133: if (this .allowInvocationsStatus == status) {
134: // we don't release and reget a latch if two identical calls are performed
135: //
136: log.debug("Invocation authorization called with no-op");
137: } else {
138: // CRITICAL CODE! DONT CHANGE ORDER WITHOUT THINKING ABOUT RACE CONDITIONS
139: //
140: if (status == MAKE_INVOCATIONS_WAIT) {
141: log
142: .debug("Invocation authorization called: MAKE_INVOCATIONS_WAIT");
143: latch = new Latch();
144: this .allowInvocationsStatus = status;
145: } else {
146: log
147: .debug("Invocation authorization called: "
148: + ((status == ENABLE_INVOCATIONS) ? "ENABLE_INVOCATIONS"
149: : "DISABLE_INVOCATIONS"));
150: this .allowInvocationsStatus = status;
151: if (latch != null)
152: latch.release();
153: }
154: }
155: }
156:
157: public boolean invocationsAllowed() throws InterruptedException {
158: if (this .allowInvocationsStatus == ENABLE_INVOCATIONS)
159: return true;
160: else if (this .allowInvocationsStatus == DISABLE_INVOCATIONS)
161: return false;
162: else if (this .allowInvocationsStatus == MAKE_INVOCATIONS_WAIT) {
163: latch.acquire();
164:
165: // if we arrive here, it means that the status has been changed, so
166: // we check for the decision:
167: //
168: if (this .allowInvocationsStatus == ENABLE_INVOCATIONS)
169: return true;
170: else
171: return false;
172: } else
173: return false;
174: }
175:
176: protected void releaseCurrentLatch() {
177: latch.release();
178: latch = null;
179: }
180:
181: public HAPartition getAssociatedPartition() {
182: return this .partition;
183: }
184:
185: // DistributedReplicantManager.ReplicantListener implementation ------------
186:
187: public void replicantsChanged(String key, List newReplicants,
188: int newReplicantsViewId) {
189: if (log.isDebugEnabled())
190: log.debug("replicantsChanged '"
191: + replicantName
192: + "' to "
193: + (newReplicants == null ? "0 (null)" : Integer
194: .toString(newReplicants.size()))
195: + " (intra-view id: " + newReplicantsViewId + ")");
196:
197: synchronized (replicants) {
198: // client has reference to replicants so it will automatically get
199: // updated
200: replicants.clear();
201: if (newReplicants != null)
202: replicants.addAll(newReplicants);
203:
204: this .clusterViewId = newReplicantsViewId;
205: }
206:
207: }
208:
209: protected void cleanExistenceInCurrentHAPartition() {
210: if (this .partition != null) {
211: try {
212: DistributedReplicantManager drm = partition
213: .getDistributedReplicantManager();
214: drm.unregisterListener(this .replicantName, this );
215: drm.remove(this .replicantName);
216: } catch (Exception e) {
217: log
218: .error(
219: "failed to clean existence in current ha partition",
220: e);
221: }
222: }
223: }
224: }
|