001// 002// Name 003// $RCSfile: QueryScope.java,v $ 004// 005// Copyright 006// Copyright 2012 Cloud Software Group, Inc. ALL RIGHTS RESERVED. 007// Cloud Software Group, Inc. Confidential Information 008// 009// History 010// $Revision: 1.1.2.2 $ $Date: 2012/08/03 19:59:24 $ 011// 012package com.kabira.platform; 013 014import java.util.HashSet; 015import java.util.Collections; 016 017/** 018 * Class used to define a set of remote nodes used for distributed queries. 019 * <p> 020 * This class allows applications to define queries that are done on 021 * a subset of nodes in the cluster. 022 * <p> 023 * When a query is executed using a user defined query scope, the current 024 * audit mode is used to verify the scope. If the default {@link 025 * com.kabira.platform.QueryScope.AuditMode#AUDIT_NODE_LIST} audit mode 026 * is enabled, distributed queries are skipped if distribution is not 027 * active when the query is executed. If distribution is active, only 028 * those nodes that are active in the node list are used in the query, 029 * all other nodes are ignored. Otherwise, the auditing documented in the 030 * {@link com.kabira.platform.QueryScope.AuditMode} enumeration is 031 * performed, and a ResourceUnavailableException exception is thrown 032 * if the audit fails. 033 * <p> 034 * When {@link QueryScope#setAuditMode(AuditMode)} is called, no audits 035 * are done at that time. Only when a query is executed is auditing done. 036 * This insures that auditing is performed before each execution of the query. 037 * <p> 038 * To support cluster wide queries, the {@link QueryScope#QUERY_CLUSTER} 039 * predefined instance of QueryScope can be used. 040 * <p> 041 * To disable node or cluster scoped queries, the {@link QueryScope#QUERY_LOCAL} 042 * predefined instance of QueryScope can be used. 043 * 044 * @see KeyQuery#setQueryScope(QueryScope) 045 * @see ManagedObject#extent(Class, QueryScope, LockMode) 046 * @see ManagedObject#cardinality(Class, QueryScope) 047 */ 048public final class QueryScope 049{ 050 /** 051 * The query will be done only on the local node. This is the default scope. 052 */ 053 public final static QueryScope QUERY_LOCAL = new QueryScope(Scope.LOCAL); 054 055 /** 056 * The query will be done on all active nodes in the cluster. 057 */ 058 public final static QueryScope QUERY_CLUSTER = new QueryScope(Scope.CLUSTER); 059 060 /** 061 * Possible audits that can be applied to the query. 062 */ 063 public enum AuditMode 064 { 065 /** 066 * Default audit mode, distributed audits are disable. The node 067 * list is validated to insure one or more nodes are defined and 068 * that no node in the list is empty. 069 */ 070 AUDIT_NODE_LIST, 071 /** 072 * Validate that the node list is valid and that distribution 073 * is active. Inactive nodes are skipped when the query is executed. 074 */ 075 AUDIT_DISTRIBUTION, 076 /** 077 * Validate that the node list is valid, distribution is active, 078 * and that all nodes are active. 079 */ 080 AUDIT_NODES_ACTIVE 081 } 082 083 /** 084 * Create a QueryScope instance with no nodes. 085 */ 086 public QueryScope() 087 { 088 m_remoteNodes = new HashSet<String>(); 089 m_scope = Scope.USER; 090 m_auditMode = AuditMode.AUDIT_NODE_LIST; 091 } 092 093 /** 094 * Create a QueryScope instance 095 * 096 * @param remoteNodes Array of remote nodes. 097 */ 098 public QueryScope(String [] remoteNodes) 099 { 100 m_remoteNodes = new HashSet<String>(); 101 Collections.addAll(m_remoteNodes, remoteNodes); 102 m_scope = Scope.USER; 103 m_auditMode = AuditMode.AUDIT_NODE_LIST; 104 } 105 106 /** 107 * Adds the specified node if not already present. 108 * @param nodeName Node to add. 109 * @exception UnsupportedOperationException 110 * The operation was called on QUERY_LOCAL or QUERY_CLUSTER. 111 */ 112 public void addNode(String nodeName) 113 throws UnsupportedOperationException 114 { 115 checkUser(); 116 m_remoteNodes.add(nodeName); 117 } 118 119 /** 120 * Removed the specified node. If not present, the remove is ignored. 121 * @param nodeName Node to remove. 122 * @exception UnsupportedOperationException 123 * The operation was called on QUERY_LOCAL or QUERY_CLUSTER. 124 */ 125 public void removeNode(String nodeName) 126 throws UnsupportedOperationException 127 { 128 checkUser(); 129 m_remoteNodes.remove(nodeName); 130 } 131 132 /** 133 * Get the nodes defined for this query scope. 134 * <p> 135 * If this method is called on QUERY_LOCAL or QUERY_CLUSTER 136 * instances, a zero length array is returned. 137 * @return Array of node names. 138 */ 139 public String [] getNodes() 140 { 141 return m_remoteNodes.toArray(new String[0]); 142 } 143 144 /** 145 * Set audit mode when queries are executed. 146 * @param auditMode Audit mode to use. 147 * @exception UnsupportedOperationException 148 * The operation was called on QUERY_LOCAL or QUERY_CLUSTER. 149 */ 150 public void setAuditMode(AuditMode auditMode) 151 throws UnsupportedOperationException 152 { 153 checkUser(); 154 m_auditMode = auditMode; 155 } 156 157 /** 158 * Return the current audit mode. 159 * @return Current audit mode. 160 * @exception UnsupportedOperationException 161 * The operation was called on QUERY_LOCAL or QUERY_CLUSTER. 162 */ 163 public AuditMode getAuditMode() 164 throws UnsupportedOperationException 165 { 166 checkUser(); 167 return m_auditMode; 168 } 169 170 // 171 // Package private definitions. 172 // 173 enum Scope 174 { 175 LOCAL, 176 CLUSTER, 177 USER 178 } 179 180 Scope getScope() 181 { 182 return m_scope; 183 } 184 185 void checkUser() throws UnsupportedOperationException 186 { 187 if (m_scope != Scope.USER) 188 { 189 throw new UnsupportedOperationException(); 190 } 191 } 192 193 void audit() 194 { 195 if (m_scope != Scope.USER) 196 { 197 assert( m_remoteNodes.isEmpty() ); 198 return; 199 } 200 201 if (m_remoteNodes.isEmpty()) 202 { 203 throw new IllegalArgumentException( 204 "The node array must have at least one entry"); 205 } 206 for (String node : m_remoteNodes) 207 { 208 if (node.isEmpty()) 209 { 210 throw new IllegalArgumentException("Empty node in list"); 211 } 212 } 213 214 if (m_auditMode == AuditMode.AUDIT_DISTRIBUTION || 215 m_auditMode == AuditMode.AUDIT_NODES_ACTIVE) 216 { 217 if (ManagedObject.m_distributedQuery == null) 218 { 219 throw new ResourceUnavailableException( 220 "Distributed query processing not available on this node"); 221 } 222 if (m_auditMode == AuditMode.AUDIT_NODES_ACTIVE) 223 { 224 ManagedObject.m_distributedQuery.validateNodesActive(this); 225 } 226 } 227 } 228 229 // 230 // Private constructor used for predefined scopes. 231 // 232 private QueryScope(Scope scope) 233 { 234 m_remoteNodes = new HashSet<String>(); 235 m_scope = scope; 236 m_auditMode = AuditMode.AUDIT_NODE_LIST; 237 } 238 239 private HashSet<String> m_remoteNodes; 240 private AuditMode m_auditMode; 241 private Scope m_scope; 242}