1 package net.sf.openrocket.database;
3 import java.util.ArrayList;
4 import java.util.Collections;
7 import net.sf.openrocket.logging.LogHelper;
8 import net.sf.openrocket.motor.Motor;
9 import net.sf.openrocket.motor.ThrustCurveMotor;
10 import net.sf.openrocket.startup.Application;
13 * A database containing ThrustCurveMotorSet objects and allowing adding a motor
16 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
18 public abstract class ThrustCurveMotorSetDatabase implements MotorDatabase {
20 private static final LogHelper logger = Application.getLogger();
22 protected List<ThrustCurveMotorSet> motorSets;
24 private volatile boolean startedLoading = false;
25 private volatile boolean endedLoading = false;
26 private final boolean asynchronous;
28 /** Set to true the first time {@link #blockUntilLoaded()} is called. */
29 protected volatile boolean inUse = false;
34 * @param asynchronous whether to load motors asynchronously in a background thread.
36 public ThrustCurveMotorSetDatabase(boolean asynchronous) {
37 this.asynchronous = asynchronous;
42 * @see net.sf.openrocket.database.ThrustCurveMotorSetDatabaseI#getMotorSets()
44 public List<ThrustCurveMotorSet> getMotorSets() {
52 * @see net.sf.openrocket.database.ThrustCurveMotorSetDatabaseI#findMotors(net.sf.openrocket.motor.Motor.Type, java.lang.String, java.lang.String, double, double)
55 public List<ThrustCurveMotor> findMotors(Motor.Type type, String manufacturer, String designation,
56 double diameter, double length) {
58 ArrayList<ThrustCurveMotor> results = new ArrayList<ThrustCurveMotor>();
60 for (ThrustCurveMotorSet set : motorSets) {
61 for (ThrustCurveMotor m : set.getMotors()) {
63 if (type != null && type != set.getType())
65 else if (manufacturer != null && !m.getManufacturer().matches(manufacturer))
67 else if (designation != null && !designation.equalsIgnoreCase(m.getDesignation()))
69 else if (!Double.isNaN(diameter) && (Math.abs(diameter - m.getDiameter()) > 0.0015))
71 else if (!Double.isNaN(length) && (Math.abs(length - m.getLength()) > 0.0015))
84 * Add a motor to the database. If a matching ThrustCurveMototSet is found,
85 * the motor is added to that set, otherwise a new set is created and added to the
88 * @param motor the motor to add
90 protected void addMotor(ThrustCurveMotor motor) {
91 // Iterate from last to first, as this is most likely to hit early when loading files
92 for (int i = motorSets.size() - 1; i >= 0; i--) {
93 ThrustCurveMotorSet set = motorSets.get(i);
94 if (set.matches(motor)) {
100 ThrustCurveMotorSet newSet = new ThrustCurveMotorSet();
101 newSet.addMotor(motor);
102 motorSets.add(newSet);
110 * Start loading the motors. If asynchronous
112 * @throws IllegalStateException if this method has already been called.
114 public void startLoading() {
115 if (startedLoading) {
116 throw new IllegalStateException("Already called startLoading");
118 startedLoading = true;
120 new LoadingThread().start();
122 performMotorLoading();
128 * Return whether loading the database has ended.
130 * @return whether background loading has ended.
132 public boolean isLoaded() {
138 * Mark that this database is in use or a place is waiting for the database to
139 * become loaded. This can be used in conjunction with {@link #isLoaded()} to load
140 * the database without blocking.
142 public void setInUse() {
148 * Block the current thread until loading of the motors has been completed.
150 * @throws IllegalStateException if startLoading() has not been called.
152 public void blockUntilLoaded() {
154 if (!startedLoading) {
155 throw new IllegalStateException("startLoading() has not been called");
158 synchronized (this) {
159 while (!endedLoading) {
162 } catch (InterruptedException e) {
163 logger.warn("InterruptedException occurred, ignoring", e);
172 * Used for loading the motor database. This method will be called in a background
173 * thread to load the motors asynchronously. This method should call
174 * {@link #addMotor(ThrustCurveMotor)} to add the motors to the database.
176 protected abstract void loadMotors();
181 * Creates the motor list, calls {@link #loadMotors()}, sorts the list and marks
182 * the motors as loaded. This method is called either synchronously or from the
185 private void performMotorLoading() {
186 motorSets = new ArrayList<ThrustCurveMotorSet>();
189 } catch (Exception e) {
190 logger.error("Loading motors failed", e);
192 Collections.sort(motorSets);
193 motorSets = Collections.unmodifiableList(motorSets);
194 synchronized (ThrustCurveMotorSetDatabase.this) {
196 ThrustCurveMotorSetDatabase.this.notifyAll();
202 * Background thread for loading the motors. This creates the motor list,
203 * calls loadMotors(), sorts the database, makes it unmodifiable, and finally
204 * marks the database as loaded and notifies any blocked threads.
206 private class LoadingThread extends Thread {
209 performMotorLoading();