KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > publishers > X10Publisher


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2004, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37 package net.sourceforge.cruisecontrol.publishers;
38
39 import com.jpeterson.x10.Gateway;
40 import com.jpeterson.x10.GatewayException;
41 import com.jpeterson.x10.SerialGateway;
42 import com.jpeterson.x10.Transmitter;
43 import com.jpeterson.x10.event.AddressEvent;
44 import com.jpeterson.x10.event.OffEvent;
45 import com.jpeterson.x10.event.OnEvent;
46 import com.jpeterson.x10.event.X10Event;
47 import com.jpeterson.x10.module.CM11A;
48 import com.jpeterson.x10.module.CM17A;
49 import net.sourceforge.cruisecontrol.CruiseControlException;
50 import net.sourceforge.cruisecontrol.Publisher;
51 import net.sourceforge.cruisecontrol.util.ValidationHelper;
52 import net.sourceforge.cruisecontrol.util.XMLLogHelper;
53 import org.apache.log4j.Logger;
54 import org.jdom.Element;
55
56 import java.io.IOException JavaDoc;
57
58 /**
59  * This Publisher implementation sends a on/off signal to a X10 capable device
60  * via the X10 Activehome computer interface, model CM11A. This allows you to
61  * control an electronic device when the build breaks. For example, use a
62  * flashing red light to indicate a broken build.
63  * <p/>
64  * NOTE: THIS PUBLISHER HAS ONLY BEEN TESTED WITH WINDOWS
65  * <p/>
66  * Quick Start:
67  * <ol>
68  * <li>Buy the home automation kit found at
69  * <a html="http://www.x10.com/automation/x10_ck11a_1.htm">http://www.x10.com/automation/x10_ck11a_1.htm</a></li>
70  * <li>Plug the computer interface to your serial port, e.g. COM1, and your powerline</li>
71  * <li>Set the lamp module's house and device code, e.g. A3, and plug it into your powerline</li>
72  * <li>Plug in an electronic device to the lamp module, e.g. a flashing red light like
73  * <a HREF="http://www.bwild.com/redsiren.html">http://www.bwild.com/redsiren.html</a></li>
74  * <li>Install the Java Communications API on your CruiseControl machine by copying the win32com.dll from the
75  * CruiseControl lib directory to your <code>JAVA_HOME/bin</code> directory</li>
76  * <li>Add the x10 publisher to CruiseControl's config.xml, e.g.
77  * <code>&lt;x10 houseCode="A" deviceCode="3" port="COM1"/&gt;</code></li>
78  * </ol>
79  * <p/>
80  * For more information about the controller, see
81  * <a html="http://www.smarthome.com/1140.html">http://www.smarthome.com/1140.html</a>
82  * or
83  * <a html="http://www.x10.com/automation/x10_ck11a_1.htm">http://www.x10.com/automation/x10_ck11a_1.htm</a>
84  * The controller connects to the computer via a serial port, e.g. COM1, and
85  * allows the computer to send (and receive) X10 signals on the power line. For
86  * more information on X10 in general, see
87  * <a HREF="http://www.x10.com/support/basicx10.htm">http://www.x10.com/support/basicx10.htm</a>.
88  * <p/>
89  * This module uses a pure Java implementation of the CM11A communication
90  * protocol as implemented by Jesse Peterson,
91  * <a HREF="http://www.jpeterson.com/">http://www.jpeterson.com/</a>. To read
92  * more about his library, see
93  * <a HREF="http://www.jpeterson.com/rnd/x101.0.1/Readme.html">http://www.jpeterson.com/rnd/x101.0.1/Readme.html</a>.
94  * <p/>
95  * The jpeterson library requires that the Java Communications API be installed.
96  * For more information on the COMM API, see
97  * <a HREF="http://java.sun.com/products/javacomm/index.jsp">http://java.sun.com/products/javacomm/index.jsp</a>.
98  * For convenience, the Java COMM API is included with the CruiseControl
99  * distribution. On windows, copy the win32com.dll from CruiseControl's lib directory to
100  * your <code>JAVA_HOME/bin</code> directory.
101  * <p/>
102  * NOTE: If you receive the following error:
103  * <PRE><CODE>Error loading win32com: java.lang.UnsatisfiedLinkError: no win32com in java.library.path</CODE></PRE>
104  * it probably means that the Windows DLL named win32com.dll needs to be copied
105  * from CruiseControl's lib directory into your JDK (or JRE) bin directory, i.e.
106  * the same directory that java.exe is found.
107  * <p/>
108  * The standard behavior for this publisher is to send the device the "on"
109  * signal when the build breaks and then the "off" signal when the build is
110  * successful. If you want the opposite, i.e. on when successful and off when
111  * broken, set the onWhenBroken attribute to false.
112  * <p/>
113  * <p/>
114  * Publisher Attributes:
115  * <ul>
116  * <li>houseCode - required - the house code for the device to control, A -> P case insensitive</li>
117  * <li>deviceCode - required - the device code the device to control, 1 -> 16</li>
118  * <li>port - optional - serial port to which the CM11A computer interface controller is
119  * connected, defaults to COM2</li>
120  * <li>onWhenBroken - optional - set to false if the device should turn on when the build is successful and off
121  * when failed, defaults to true</li>
122  * <li>interfaceMode - optional - set to either CM11A or CM17A depending on the model of the X10 computer interface
123  * being used, defaults to CM11A</li>
124  * </ul>
125  *
126  * @author <a HREF="mailto:pauljulius@users.sourceforge.net">Paul Julius</a>
127  * @since August 26 2004
128  */

129 public class X10Publisher implements Publisher {
130     private static final Logger LOG = Logger.getLogger(X10Publisher.class);
131
132     private String JavaDoc houseCode;
133     private String JavaDoc deviceCode;
134     private String JavaDoc port;
135     private boolean onWhenBroken = true;
136     private String JavaDoc interfaceModel;
137
138     public void publish(Element cruisecontrolLog)
139             throws CruiseControlException {
140
141         XMLLogHelper logHelper = new XMLLogHelper(cruisecontrolLog);
142         handleBuild(!logHelper.isBuildSuccessful());
143     }
144
145     public void handleBuild(boolean isBroken) throws CruiseControlException {
146         if ((isBroken && onWhenBroken) || (!isBroken && !onWhenBroken)) {
147             turnOn();
148         } else {
149             turnOff();
150         }
151     }
152
153     public void turnOn() throws CruiseControlException {
154         final char houseCodeChar = houseCode.charAt(0);
155         final int deviceCodeInt = Integer.valueOf(deviceCode).intValue();
156
157         X10Event[] events = new X10Event[ 2 ];
158         events[ 0 ] = new AddressEvent(this, houseCodeChar, deviceCodeInt);
159         events[ 1 ] = new OnEvent(this, houseCodeChar);
160
161         send(events);
162     }
163
164     public void turnOff() throws CruiseControlException {
165         final char houseCodeChar = houseCode.charAt(0);
166         final int deviceCodeInt = Integer.valueOf(deviceCode).intValue();
167
168         X10Event[] events = new X10Event[ 2 ];
169         events[ 0 ] = new AddressEvent(this, houseCodeChar, deviceCodeInt);
170         events[ 1 ] = new OffEvent(this, houseCodeChar);
171
172         send(events);
173
174     }
175
176     private void send(X10Event[] events) throws CruiseControlException {
177         LOG.info("Sending X10 events...");
178         Transmitter transmitter = getTransmitter();
179         if (port != null) {
180             ((SerialGateway) transmitter).setPortName(port);
181         }
182         try {
183             ((Gateway) transmitter).allocate();
184         } catch (Exception JavaDoc e) {
185             throw new CruiseControlException("Trouble allocating the x10 gateway.", e);
186         }
187
188         for (int j = 0; j < events.length; j++) {
189             LOG.debug("Transmitting: " + events[ j ]);
190             try {
191                 transmitter.transmit(events[ j ]);
192             } catch (IOException JavaDoc e) {
193                 throw new CruiseControlException("Trouble transmitting event " + events[ j ], e);
194             }
195         }
196
197         if (transmitter instanceof Gateway) {
198             Gateway gateway = (Gateway) transmitter;
199
200             try {
201                 LOG.debug("Wait for empty queue...");
202                 gateway.waitGatewayState(Transmitter.QUEUE_EMPTY);
203                 LOG.debug("Done");
204             } catch (InterruptedException JavaDoc e) {
205             }
206
207             LOG.debug("Deallocating...");
208             try {
209                 gateway.deallocate();
210             } catch (GatewayException e) {
211                 LOG.warn("Error deallocation gateway: " + e.getMessage(), e);
212             }
213             LOG.debug("Done");
214         }
215         LOG.debug("Done sending X10 events...");
216     }
217
218     protected Transmitter getTransmitter() throws CruiseControlException {
219         if (interfaceModel != null && interfaceModel.equalsIgnoreCase("CM17A")) {
220             return new CM17A();
221         } else if (interfaceModel == null || interfaceModel.equals("") || interfaceModel.equalsIgnoreCase("CM11A")) {
222             return new CM11A();
223         } else {
224             throw new CruiseControlException("Unknown interface model specified [" + interfaceModel + "].");
225         }
226     }
227
228     public void validate() throws CruiseControlException {
229         ValidationHelper.assertFalse(houseCode == null || deviceCode == null,
230                 "Both houseCode and deviceCode are required fields.");
231
232         ValidationHelper.assertTrue(isLegalHouseCode(houseCode),
233             "The house code must be a single alphabetic "
234                     + "letter between A and P, inclusive. You specified ["
235                     + houseCode
236                     + "].");
237
238         ValidationHelper.assertTrue(isLegalDeviceCode(deviceCode),
239             "The device code must be an integer between"
240                     + " 1 and 16, inclusive. You specified ["
241                     + deviceCode + "]");
242
243         ValidationHelper.assertTrue(isLegalInterfaceModel(interfaceModel),
244             "The interface model must is not a legal value. You specified ["
245                     + deviceCode + "]");
246     }
247
248     private static boolean isLegalInterfaceModel(String JavaDoc model) {
249         return model == null
250                 || "".equals(model)
251                 || "cm11a".equalsIgnoreCase(model)
252                 || "cm17a".equalsIgnoreCase(model);
253     }
254
255     private static boolean isLegalDeviceCode(String JavaDoc deviceCode) {
256         return "1".equals(deviceCode)
257                 || "2".equals(deviceCode)
258                 || "3".equals(deviceCode)
259                 || "4".equals(deviceCode)
260                 || "5".equals(deviceCode)
261                 || "6".equals(deviceCode)
262                 || "7".equals(deviceCode)
263                 || "8".equals(deviceCode)
264                 || "9".equals(deviceCode)
265                 || "10".equals(deviceCode)
266                 || "11".equals(deviceCode)
267                 || "12".equals(deviceCode)
268                 || "13".equals(deviceCode)
269                 || "14".equals(deviceCode)
270                 || "15".equals(deviceCode)
271                 || "16".equals(deviceCode);
272     }
273
274     private static boolean isLegalHouseCode(String JavaDoc houseCode) {
275         return "A".equalsIgnoreCase(houseCode)
276                 || "B".equalsIgnoreCase(houseCode)
277                 || "C".equalsIgnoreCase(houseCode)
278                 || "D".equalsIgnoreCase(houseCode)
279                 || "E".equalsIgnoreCase(houseCode)
280                 || "F".equalsIgnoreCase(houseCode)
281                 || "G".equalsIgnoreCase(houseCode)
282                 || "H".equalsIgnoreCase(houseCode)
283                 || "I".equalsIgnoreCase(houseCode)
284                 || "J".equalsIgnoreCase(houseCode)
285                 || "K".equalsIgnoreCase(houseCode)
286                 || "L".equalsIgnoreCase(houseCode)
287                 || "M".equalsIgnoreCase(houseCode)
288                 || "N".equalsIgnoreCase(houseCode)
289                 || "O".equalsIgnoreCase(houseCode)
290                 || "P".equalsIgnoreCase(houseCode);
291     }
292
293     public void setHouseCode(String JavaDoc code) {
294         this.houseCode = code;
295     }
296
297     public void setDeviceCode(String JavaDoc code) {
298         this.deviceCode = code;
299     }
300
301     /**
302      * The x10 cm11a library defaults to com2 for the port, so this
303      * attribute is optional.
304      */

305     public void setPort(String JavaDoc portName) {
306         this.port = portName;
307     }
308
309     public void setOnWhenBroken(boolean shouldTurnOn) {
310         this.onWhenBroken = shouldTurnOn;
311     }
312
313     public void setInterfaceModel(String JavaDoc model) {
314         this.interfaceModel = model;
315     }
316 }
317
Popular Tags