001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
006: * Copyright (C) 2006 Continuent, Inc.
007: * Contact: sequoia@continuent.org
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: *
021: * Initial developer(s): Emmanuel Cecchet.
022: * Contributor(s): ______________________.
023: */package org.continuent.sequoia.controller.virtualdatabase.protocol;
024:
025: import java.io.Serializable;
026: import java.util.ArrayList;
027: import java.util.List;
028:
029: import org.continuent.hedera.common.Member;
030: import org.continuent.sequoia.common.i18n.Translate;
031: import org.continuent.sequoia.common.jmx.JmxConstants;
032: import org.continuent.sequoia.common.jmx.management.BackendInfo;
033: import org.continuent.sequoia.common.log.Trace;
034: import org.continuent.sequoia.controller.backend.DatabaseBackend;
035: import org.continuent.sequoia.controller.jmx.RmiConnector;
036: import org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager;
037: import org.continuent.sequoia.controller.virtualdatabase.DistributedVirtualDatabase;
038:
039: /**
040: * Transports the configuration of a virtual database to remote controllers so
041: * that compatibility checking can be performed.
042: *
043: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
044: * @version 1.0
045: */
046: public class VirtualDatabaseConfiguration extends
047: DistributedVirtualDatabaseMessage {
048: private static final long serialVersionUID = -4753828540599620782L;
049:
050: private String controllerName;
051: private String controllerJmxName;
052: private String vdbName;
053: private String groupName = null;
054: private ArrayList vLogins;
055: private int schedulerRAIDbLevel;
056: private int loadBalancerRAIDbLevel;
057: private List /* <BackendInfo> */backendInfos;
058:
059: // Jmx Information
060: private String rmiHostname;
061: private String rmiPort;
062:
063: /**
064: * @return Returns the controllerName.
065: */
066: public String getControllerName() {
067: return controllerName;
068: }
069:
070: /**
071: * Returns the controllerJmxName value.
072: *
073: * @return Returns the controllerJmxName.
074: */
075: public String getControllerJmxName() {
076: return controllerJmxName;
077: }
078:
079: /**
080: * Constructs a new <code>VirtualDatabaseConfiguration</code> object from a
081: * <code>DistributedVirtualDatabase</code>.
082: *
083: * @param dvdb The distributed virtual database to get configuration from.
084: */
085: public VirtualDatabaseConfiguration(DistributedVirtualDatabase dvdb) {
086: this .controllerName = dvdb.getControllerName();
087: this .controllerJmxName = dvdb.viewOwningController();
088: this .vdbName = dvdb.getVirtualDatabaseName();
089: this .groupName = dvdb.getGroupName();
090: this .vLogins = dvdb.getAuthenticationManager()
091: .getVirtualLogins();
092: this .schedulerRAIDbLevel = dvdb.getRequestManager()
093: .getScheduler().getRAIDbLevel();
094: this .loadBalancerRAIDbLevel = dvdb.getRequestManager()
095: .getLoadBalancer().getRAIDbLevel();
096: this .backendInfos = DatabaseBackend.toBackendInfos(dvdb
097: .getBackends());
098:
099: List connectors = RmiConnector.getRmiConnectors();
100: if (connectors.size() > 0) {
101: RmiConnector rmi = (RmiConnector) connectors.get(0);
102: rmiHostname = rmi.getHostName();
103: rmiPort = String.valueOf(rmi.getPort());
104: } else {
105: rmiHostname = controllerName.substring(0, controllerName
106: .indexOf(":"));
107: rmiPort = String.valueOf(JmxConstants.DEFAULT_JMX_RMI_PORT);
108: }
109: }
110:
111: /**
112: * @return Returns the rmiHostname.
113: */
114: public String getRmiHostname() {
115: return rmiHostname;
116: }
117:
118: /**
119: * @return Returns the rmiPort.
120: */
121: public String getRmiPort() {
122: return rmiPort;
123: }
124:
125: /**
126: * Check if the local distributed virtual database is compatible with this
127: * virtual database configuration.
128: *
129: * @param localDvdb The local distributed virtual database
130: * @return an array of objects containing:
131: * <ul>
132: * <li>Boolean.TRUE if both configurations are compatible,
133: * Boolean.FALSE otherwise
134: * <li>a List of VirtualDatabaseUser objects if there are missing vdb
135: * users, null otherwise
136: * </ul>
137: */
138: private Object[] isCompatible(DistributedVirtualDatabase localDvdb) {
139: Object[] ret = new Object[2];
140: ret[0] = Boolean.FALSE;
141: ret[1] = null;
142: try {
143: if (controllerName.equals(localDvdb.getControllerName())) {
144: localDvdb
145: .getLogger()
146: .warn(
147: Translate
148: .get("virtualdatabase.distributed.configuration.checking.duplicate.controller.name"));
149: return ret;
150: }
151:
152: // Sanity checks for virtual database name and group name
153: if (!vdbName.equals(localDvdb.getVirtualDatabaseName())) {
154: localDvdb
155: .getLogger()
156: .warn(
157: Translate
158: .get("virtualdatabase.distributed.configuration.checking.mismatch.name"));
159: return ret;
160: }
161: if (!groupName.equals(localDvdb.getGroupName())) {
162: localDvdb
163: .getLogger()
164: .warn(
165: Translate
166: .get("virtualdatabase.distributed.configuration.checking.mismatch.groupname"));
167: return ret;
168: }
169:
170: // Scheduler and Load Balancer checking
171: if (schedulerRAIDbLevel != localDvdb.getRequestManager()
172: .getScheduler().getRAIDbLevel()) {
173: localDvdb
174: .getLogger()
175: .warn(
176: Translate
177: .get("virtualdatabase.distributed.configuration.checking.mismatch.scheduler"));
178: return ret;
179: }
180:
181: if (loadBalancerRAIDbLevel != localDvdb.getRequestManager()
182: .getLoadBalancer().getRAIDbLevel()) {
183: localDvdb
184: .getLogger()
185: .warn(
186: Translate
187: .get("virtualdatabase.distributed.configuration.checking.mismatch.loadbalancer"));
188: return ret;
189: }
190:
191: // Checking backendInfos
192: int size = backendInfos.size();
193: for (int i = 0; i < size; i++) {
194: BackendInfo b = (BackendInfo) backendInfos.get(i);
195: if (!localDvdb.isCompatibleBackend(b)) {
196: localDvdb
197: .getLogger()
198: .warn(
199: Translate
200: .get(
201: "virtualdatabase.distributed.configuration.checking.mismatch.backend.shared",
202: b.getName()));
203: return ret;
204: }
205: }
206:
207: // Authentication managers must contains the same set of elements but
208: // possibly in different orders (equals require the element to be in the
209: // same order).
210: if (!localDvdb.getAuthenticationManager()
211: .getVirtualLogins().containsAll(vLogins)) {
212: localDvdb
213: .getLogger()
214: .warn(
215: Translate
216: .get("virtualdatabase.distributed.configuration.checking.mismatch.vlogins"));
217: return ret;
218: }
219:
220: // Special case: the joining vdb will try to become compatible by
221: // dynamically creating the missing vd users.
222: // WARNING: don't move this test around, it does expect to be the last
223: // test performed, meaning that if missing vdb users can be added the
224: // configurations will effectively become compatible.
225: if (!vLogins.containsAll(localDvdb
226: .getAuthenticationManager().getVirtualLogins())) {
227: localDvdb
228: .getLogger()
229: .warn(
230: Translate
231: .get("virtualdatabase.distributed.configuration.checking.mismatch.vlogins"));
232: List additionalVdbUsers = new ArrayList(localDvdb
233: .getAuthenticationManager().getVirtualLogins());
234: additionalVdbUsers.removeAll(vLogins);
235: ret[0] = Boolean.TRUE;
236: ret[1] = additionalVdbUsers;
237: return ret;
238: }
239:
240: // Ok, all tests succeeded, configuration is compatible
241: ret[0] = Boolean.TRUE;
242: return ret;
243: } catch (Exception e) {
244: localDvdb
245: .getLogger()
246: .error(
247: Translate
248: .get("virtualdatabase.distributed.configuration.checking.error"),
249: e);
250: return ret;
251: }
252: }
253:
254: /**
255: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedVirtualDatabaseMessage#handleMessageSingleThreaded(org.continuent.sequoia.controller.virtualdatabase.DistributedVirtualDatabase,
256: * org.continuent.hedera.common.Member)
257: */
258: public Object handleMessageSingleThreaded(
259: DistributedVirtualDatabase dvdb, Member sender) {
260: return null;
261: }
262:
263: /**
264: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedVirtualDatabaseMessage#handleMessageMultiThreaded(org.continuent.sequoia.controller.virtualdatabase.DistributedVirtualDatabase,
265: * org.continuent.hedera.common.Member, java.lang.Object)
266: */
267: public Serializable handleMessageMultiThreaded(
268: DistributedVirtualDatabase dvdb, Member sender,
269: Object handleMessageSingleThreadedResult) {
270: Trace logger = dvdb.getLogger();
271: if (logger.isInfoEnabled())
272: logger.info("Checking virtual database configuration from "
273: + getControllerName());
274:
275: Object[] ret = isCompatible(dvdb);
276: if (!dvdb.isLocalSender(sender)
277: && !((Boolean) ret[0]).booleanValue()) {
278: // Failure
279: return new VirtualDatabaseConfigurationResponse(
280: DistributedVirtualDatabase.INCOMPATIBLE_CONFIGURATION,
281: (List) ret[1]);
282: }
283:
284: // Configuration is compatible, add it to our controller list
285: dvdb.addRemoteControllerJmxName(sender, controllerJmxName);
286:
287: // Send back our local configuration
288: try {
289: dvdb.sendLocalConfiguration(sender);
290: } catch (Exception e) {
291: return e;
292: }
293:
294: if (logger.isInfoEnabled())
295: logger.info("Controller " + getControllerName()
296: + " is compatible with the local configuration");
297: return new VirtualDatabaseConfigurationResponse(
298: ((DistributedRequestManager) dvdb.getRequestManager())
299: .getControllerId(), (List) ret[1]);
300: }
301:
302: }
|