001: /*
002: * (c) Copyright 2007 by Volker Bergmann. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, is permitted under the terms of the
006: * GNU General Public License.
007: *
008: * For redistributing this software or a derivative work under a license other
009: * than the GPL-compatible Free Software License as defined by the Free
010: * Software Foundation or approved by OSI, you must first obtain a commercial
011: * license to this software product from Volker Bergmann.
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
014: * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
015: * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
016: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
017: * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
018: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
019: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
020: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
021: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
022: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
023: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGE.
025: */
026:
027: package org.databene.model.depend;
028:
029: import java.util.ArrayList;
030: import java.util.List;
031:
032: import static org.databene.model.depend.NodeState.*;
033:
034: /**
035: * Helper class for calculating dependencies.
036: * @author Volker Bergmann
037: * @since 0.3.04
038: * @param <E>
039: */
040: class Node<E extends Dependent<E>> {
041:
042: private NodeState state;
043:
044: private E subject;
045: private List<Node<E>> providers;
046: private List<Boolean> providerRequired;
047: private List<Node<E>> clients;
048:
049: public Node(E subject) {
050: super ();
051: this .subject = subject;
052: this .providers = new ArrayList<Node<E>>();
053: this .providerRequired = new ArrayList<Boolean>();
054: this .clients = new ArrayList<Node<E>>();
055: this .state = INITIALIZABLE;
056: }
057:
058: // properties ------------------------------------------------------------------------------------------------------
059:
060: /**
061: * @return the subject
062: */
063: public E getSubject() {
064: return subject;
065: }
066:
067: /**
068: * @return the state
069: */
070: public NodeState getState() {
071: return state;
072: }
073:
074: public boolean requires(Node<E> provider) {
075: return providerRequired.get(providers.indexOf(provider));
076: }
077:
078: public List<Node<E>> getProviders() {
079: return providers;
080: }
081:
082: public Node<E> addProvider(Node<E> provider, boolean required) {
083: this .state = INACTIVE;
084: if (this .providers.contains(provider)) {
085: if (required && !required(provider)) {
086: providerRequired.set(providers.indexOf(provider),
087: Boolean.TRUE);
088: providersChanged();
089: }
090: } else {
091: this .providers.add(provider);
092: this .providerRequired.add(required);
093: provider.addClient(this );
094: providersChanged();
095: }
096: return this ;
097: }
098:
099: public boolean hasProviders() {
100: return (providers.size() > 0);
101: }
102:
103: public boolean required(Node<E> provider) {
104: return providerRequired.get(providers.indexOf(provider));
105: }
106:
107: public List<Node<E>> getClients() {
108: return clients;
109: }
110:
111: public void addClient(Node<E> client) {
112: if (!this .clients.contains(client))
113: this .clients.add(client);
114: }
115:
116: public boolean hasClients() {
117: return (clients.size() > 0);
118: }
119:
120: // interface -------------------------------------------------------------------------------------------------------
121:
122: void providersChanged() {
123: if (state == INITIALIZABLE || state == INITIALIZED)
124: return;
125: // check initializability
126: boolean initializable = true;
127: boolean partiallyInitializable = true;
128: for (Node<E> provider : providers)
129: if (!allowsClientInitialization(provider.getState())) {
130: initializable = false;
131: if (required(provider))
132: partiallyInitializable = false;
133: }
134: if (initializable) {
135: this .state = INITIALIZABLE;
136: return;
137: }
138: if (state == PARTIALLY_INITIALIZED)
139: return;
140: if (partiallyInitializable) {
141: this .state = PARTIALLY_INITIALIZABLE;
142: return;
143: }
144: if (state != INACTIVE)
145: return;
146: if (!hasProviders())
147: this .state = FORCEABLE;
148: for (Node<E> provider : providers)
149: if (provider.getState() == INITIALIZED) {
150: this .state = FORCEABLE;
151: return;
152: }
153: }
154:
155: private boolean allowsClientInitialization(NodeState providerState) {
156: return providerState == INITIALIZED || providerState == FORCED
157: || providerState == PARTIALLY_INITIALIZED;
158: }
159:
160: /*
161: private boolean allProvidersInState(NodeState state) {
162: for (Node<E> provider : providers)
163: if (provider.getState() != state)
164: return false;
165: return true;
166: }
167: */
168: public void initialize() {
169: if (state != INITIALIZABLE)
170: throw new IllegalStateException("Node not initializable: "
171: + this );
172: setState(INITIALIZED);
173: }
174:
175: private void setState(NodeState state) {
176: this .state = state;
177: for (Node<E> client : clients)
178: client.providersChanged();
179: }
180:
181: public void initializePartially() {
182: if (state != PARTIALLY_INITIALIZABLE)
183: throw new IllegalStateException(
184: "Node not partially initializable: " + this );
185: setState(PARTIALLY_INITIALIZED);
186: }
187:
188: public void force() {
189: setState(FORCED);
190: }
191:
192: void assertState(NodeState state) {
193: if (this .state != state)
194: throw new IllegalStateException("Expected to be in state '"
195: + state + "', " + "found: '" + this .state + "'");
196: }
197:
198: // java.lang.Object ------------------------------------------------------------------------------------------------
199:
200: @Override
201: public int hashCode() {
202: return subject.hashCode();
203: }
204:
205: @Override
206: public boolean equals(Object obj) {
207: if (this == obj)
208: return true;
209: if (obj == null || getClass() != obj.getClass())
210: return false;
211: final Node<E> that = (Node<E>) obj;
212: return (this .subject != null ? this .subject
213: .equals(that.subject) : that.subject == null);
214: }
215:
216: @Override
217: public String toString() {
218: return subject.toString();
219: }
220:
221: }
|