001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.gps.device;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.compass.gps.ActiveMirrorGpsDevice;
022: import org.compass.gps.CompassGpsDevice;
023: import org.compass.gps.CompassGpsException;
024:
025: /**
026: * For {@link org.compass.gps.ActiveMirrorGpsDevice}s, the schedule mirror
027: * device can call the
028: * {@link org.compass.gps.ActiveMirrorGpsDevice#performMirroring()} in a
029: * scheduled manner by wrapping the actual
030: * {@link org.compass.gps.ActiveMirrorGpsDevice}.
031: * <p/>
032: * The schedule mirror gps device implements the
033: * {@link org.compass.gps.ActiveMirrorGpsDevice} interface, and provides access
034: * to the wrapped gps device using the {@link #getWrappedGpsDevice()}.
035: * <p/>
036: * For scheduling, the schedule mirror device uses the
037: * <code>java.util.Timer</code>, and provides controll over the period,
038: * daemon, and fixed rate parameters.
039: *
040: * @author kimchy
041: */
042: public class ScheduledMirrorGpsDevice extends
043: AbstractMirrorGpsDeviceWrapper implements ActiveMirrorGpsDevice {
044:
045: private static Log log = LogFactory
046: .getLog(ScheduledMirrorGpsDevice.class);
047:
048: private ActiveMirrorGpsDevice gpsDevice;
049:
050: private MirrorGpsDeviceThread thread;
051:
052: private boolean daemon = true;
053:
054: private long period = 10000;
055:
056: /**
057: * Creates a new instance. Note that the wrapped gps device must be set by
058: * calling the <code>setGpsDevice</code> and it must implement the .
059: */
060: public ScheduledMirrorGpsDevice() {
061: }
062:
063: /**
064: * Creates a new instance of the scheduled device with the wrapped
065: * {@link ActiveMirrorGpsDevice} initialized.
066: *
067: * @param gpsDevice
068: */
069: public ScheduledMirrorGpsDevice(ActiveMirrorGpsDevice gpsDevice) {
070: this .gpsDevice = gpsDevice;
071: setGpsDevice(gpsDevice);
072: }
073:
074: /**
075: * Checks that when setting the wrapped gps device, it is of type
076: * {@link ActiveMirrorGpsDevice}
077: */
078: public void setGpsDevice(CompassGpsDevice gpsDevice) {
079: if (!(gpsDevice instanceof ActiveMirrorGpsDevice)) {
080: throw new IllegalArgumentException(
081: "The device must implement the ActiveMirrorGpsDevice interface");
082: }
083: this .gpsDevice = (ActiveMirrorGpsDevice) gpsDevice;
084: super .setGpsDevice(gpsDevice);
085: }
086:
087: /**
088: * Starts the scheduled timer.
089: */
090: public synchronized void start() throws CompassGpsException {
091: if (isRunning()) {
092: throw new IllegalStateException("{" + getName()
093: + "} Scheduled mirror device is already running");
094: }
095: if (log.isInfoEnabled()) {
096: log
097: .info("{"
098: + getName()
099: + "} Starting scheduled mirror device with period ["
100: + period + "ms] daemon [" + daemon + "]");
101: }
102: this .gpsDevice.start();
103: thread = new MirrorGpsDeviceThread(period);
104: thread.setName("Compass Mirror Gps Device [" + getName() + "]");
105: thread.start();
106: }
107:
108: /**
109: * Stops the scheduled timer.
110: */
111: public synchronized void stop() throws CompassGpsException {
112: if (!isRunning()) {
113: throw new IllegalStateException("{" + getName()
114: + "} Scheduled mirror device is already running");
115: }
116: if (log.isInfoEnabled()) {
117: log.info("{" + getName()
118: + "} Stopping scheduled mirror device");
119: }
120: thread.cancel();
121: thread = null;
122: this .gpsDevice.stop();
123: }
124:
125: /**
126: * Returns the wrapped active mirror gps device.
127: */
128: public ActiveMirrorGpsDevice getWrappedGpsDevice() {
129: return gpsDevice;
130: }
131:
132: /**
133: * Sets the wrapped gps device.
134: */
135: public void setWrappedGpsDevice(ActiveMirrorGpsDevice gpsDevice) {
136: this .gpsDevice = gpsDevice;
137: setGpsDevice(gpsDevice);
138: }
139:
140: /**
141: * Performs the actual mirror operation, delegating the action to the
142: * wrapped gps device.
143: */
144: public void performMirroring() throws CompassGpsException {
145: checkDeviceSet();
146: this .gpsDevice.performMirroring();
147: }
148:
149: /**
150: * If the scheduled timer whould work as a daemon thread or not.
151: */
152: public boolean isDaemon() {
153: return daemon;
154: }
155:
156: /**
157: * Sets if the scheduled timer would work as a daemon thread or not.
158: */
159: public void setDaemon(boolean daemon) {
160: this .daemon = daemon;
161: }
162:
163: /**
164: * The period of the scheduled service in milli-seconds.
165: */
166: public long getPeriod() {
167: return period;
168: }
169:
170: /**
171: * Sets the period of the scheduled service in milli-seconds.
172: *
173: * @param period
174: */
175: public void setPeriod(long period) {
176: this .period = period;
177: }
178:
179: private class MirrorGpsDeviceThread extends Thread {
180:
181: private long period;
182:
183: private boolean canceled;
184:
185: public MirrorGpsDeviceThread(long period) {
186: this .period = period;
187: }
188:
189: public void run() {
190: while (!Thread.interrupted() || !canceled) {
191: try {
192: Thread.sleep(period);
193: } catch (InterruptedException e) {
194: break;
195: }
196: try {
197: gpsDevice.performMirroring();
198: } catch (Exception e) {
199: log.warn("Failed to perform gps device mirroring",
200: e);
201: }
202: }
203: }
204:
205: public void cancel() {
206: this .canceled = true;
207: this.interrupt();
208: }
209: }
210: }
|