package com.framsticks.util.dispatching; import java.util.AbstractCollection; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import com.framsticks.params.ParamFlags; import com.framsticks.params.annotations.AutoAppendAnnotation; import com.framsticks.params.annotations.FramsClassAnnotation; import com.framsticks.params.annotations.ParamAnnotation; import com.framsticks.util.FramsticksException; import com.framsticks.util.Misc; @FramsClassAnnotation public class JoinableCollection extends AbstractJoinable implements JoinableParent, Iterable { protected final Set joinables = new HashSet(); protected boolean finishIfOne; protected String observableName; public JoinableCollection() { this(false); } public JoinableCollection(boolean finishIfOne) { this.finishIfOne = finishIfOne; } @AutoAppendAnnotation public synchronized void add(T joinable) { if (this.state.ordinal() > JoinableState.RUNNING.ordinal()) { throw new FramsticksException().msg("failed to add joinable - collection is passed running state").arg("joinable", joinable).arg("collection", this); } if (joinables.contains(joinable)) { throw new FramsticksException().msg("joinable is already observed").arg("joinable", joinable).arg("in", this); } joinables.add(joinable); if (this.state.equals(JoinableState.RUNNING)) { Dispatching.use(joinable, this); } } public synchronized void remove(T joinable) { if (this.state.ordinal() > JoinableState.RUNNING.ordinal()) { throw new FramsticksException().msg("failed to remote joinable - collection is passed running state").arg("joinable", joinable).arg("collection", this); } if (!joinables.contains(joinable)) { throw new FramsticksException().msg("joinable is not observed").arg("joinable", joinable).arg("in", this); } joinables.remove(joinable); if (this.state.equals(JoinableState.RUNNING)) { Dispatching.drop(joinable, this); } } @Override protected void joinableStart() { for (T j : joinables) { Dispatching.use(j, this); } } @Override protected void joinableInterrupt() { if (joinables.isEmpty()) { finishJoinable(); return; } for (T j : joinables) { Dispatching.drop(j, this); } } @Override protected void joinableFinish() { } @Override protected void joinableJoin() throws InterruptedException { for (T j : joinables) { Dispatching.join(j); } } protected JoinableState getNextState() { if (joinables.isEmpty()) { return state; } JoinableState result = finishIfOne ? JoinableState.INITILIAZED : JoinableState.JOINED; for (Joinable j : joinables) { JoinableState s = j.getState(); if (finishIfOne) { if (s.ordinal() > result.ordinal()) { result = s; } } else { if (s.ordinal() < result.ordinal()) { result = s; } } } return result; } @Override public void childChangedState(Joinable joinable, JoinableState state) { proceedToState(getNextState()); } @Override public Iterator iterator() { return Collections.unmodifiableSet(joinables).iterator(); } @Override public String toString() { return Misc.returnNotNull(observableName, "collection"); } /** * @param observableName the observableName to set */ public JoinableCollection setObservableName(String observableName) { this.observableName = observableName; return this; } public T get(String name) { for (T j : joinables) { if (name.equals(j.getName())) { return j; } } return null; } public int size() { return joinables.size(); } public boolean contains(T joinable) { return joinables.contains(joinable); } @Override @ParamAnnotation public String getName() { return observableName; } @ParamAnnotation(flags = ParamFlags.USERREADONLY) public final void setName(String name) { observableName = name; } public Collection asCollection() { return new AbstractCollection() { @Override public Iterator iterator() { return JoinableCollection.this.iterator(); } @Override public int size() { return JoinableCollection.this.size(); } @Override public boolean add(T joinable) { JoinableCollection.this.add(joinable); return true; } @SuppressWarnings("unchecked") @Override public boolean remove(Object joinable) { JoinableCollection.this.remove((T) joinable); return true; } }; } }