View Javadoc

1   /*
2    * Copyright (c) 2014. Peter Crossley (xley.com)
3    *  Licensed to the Apache Software Foundation (ASF) under one
4    *  or more contributor license agreements.  See the NOTICE file
5    *  distributed with this work for additional information
6    *  regarding copyright ownership.  The ASF licenses this file
7    *  to you under the Apache License, Version 2.0 (the
8    *  "License"); you may not use this file except in compliance
9    *  with the License.  You may obtain a copy of the License at
10   *
11   *    http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *  Unless required by applicable law or agreed to in writing,
14   *  software distributed under the License is distributed on an
15   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   *  KIND, either express or implied.  See the License for the
17   *  specific language governing permissions and limitations
18   *  under the License.
19   */
20  
21  package com.xley.lfosc.impl;
22  
23  import com.illposed.osc.OSCMessage;
24  import com.illposed.osc.OSCPortOut;
25  import com.xley.lfosc.util.LogUtil;
26  
27  import java.io.IOException;
28  import java.io.UnsupportedEncodingException;
29  import java.net.InetAddress;
30  import java.net.SocketException;
31  import java.net.UnknownHostException;
32  import java.nio.charset.Charset;
33  import java.text.MessageFormat;
34  import java.util.Locale;
35  import java.util.ResourceBundle;
36  import java.util.regex.Matcher;
37  import java.util.regex.Pattern;
38  
39  /**
40   * The type OSC proxy protocol.
41   */
42  public class LightFactoryProtocol {
43      /**
44       * The constant resources.
45       */
46      public static final ResourceBundle resources = ResourceBundle.getBundle(LightFactoryProtocol.class.getSimpleName(),
47              Locale.getDefault());
48      /**
49       * The constant osc pattern.
50       */
51      protected static final Pattern oscPattern = Pattern.compile("^osc@(.*):(\\d+)\\s+(\\/\\S+)(.*)$",
52              Pattern.CASE_INSENSITIVE + Pattern.MULTILINE);
53      /**
54       * The constant data pattern.
55       */
56      protected static final Pattern dataPattern = Pattern.
57              compile("((\"((?<token>.*?)(?<!\\\\)\")|(?<token1>[\\S]+))(\\s)*)",
58                      Pattern.CASE_INSENSITIVE + Pattern.MULTILINE);
59  
60  
61      /**
62       * Address section of the LF command.
63       */
64      private static final int PARTS_ADDRESS = 1;
65      /**
66       * Port for the address section of the LF command.
67       */
68      private static final int PARTS_PORTS = 2;
69      /**
70       * OSC container section from the LF command.
71       */
72      private static final int PARTS_CONTAINER = 3;
73      /**
74       * OSC data section from the LF command.
75       */
76      private static final int PARTS_DATA = 4;
77  
78  
79      /**
80       * Process incoming LightFactory remote command.
81       * <br/><b>Example input:</b> <i>osc@address:port /first/this/one data</i>
82       *
83       * @param cmd the the input from LightFactory
84       * @return the string
85       */
86      protected final String process(final String cmd) {
87  
88          /**
89           * 1. parse input syntax
90           *   osc@address:port /first/this/one data
91           */
92          final String command = cmd.toLowerCase();
93          boolean sent = false;
94          Matcher matches = oscPattern.matcher(command);
95          try {
96              //find the address and verify
97              while (matches.find()) {
98                  LogUtil.debug(this.getClass(), resources.getString("lf.event.valid"));
99                  String address = matches.group(PARTS_ADDRESS);
100                 int port = Integer.parseInt(matches.group(PARTS_PORTS));
101                 String container = matches.group(PARTS_CONTAINER);
102                 String data = matches.group(PARTS_DATA);
103                 OSCPortOut oscPortOut = null;
104 
105                 try {
106                     LogUtil.debug(this.getClass(), MessageFormat.format(resources.getString("lf.osc.port.connect"),
107                             address, port));
108 
109                     OSCMessage message = new OSCMessage(container);
110 
111                     if (data != null && data.length() > 0) {
112                         Matcher dataMatches = dataPattern.matcher(data);
113                         while (dataMatches.find()) {
114                             message.addArgument(convertToOSCType(dataMatches.group(2)));
115                         }
116                     }
117 
118                     LogUtil.debug(this.getClass(), MessageFormat.format(resources.getString("lf.osc.port.send"),
119                             message.getAddress(), String.valueOf(message.getArguments()),
120                             address, port));
121 
122                     //send the packet
123                     oscPortOut = new OSCPortOut(InetAddress.getByName(address), port);
124                     oscPortOut.send(message);
125                     sent = true;
126                 } finally {
127                     if (oscPortOut != null) {
128                         oscPortOut.close();
129                         LogUtil.debug(this.getClass(), MessageFormat.format(resources.getString("lf.osc.port.close"),
130                                 address, port));
131                     }
132                 }
133             }
134 
135         } catch (UnknownHostException e) {
136             return MessageFormat.format(resources.getString("lf.osc.error.unknownhost"), e.getMessage());
137         } catch (UnsupportedEncodingException e) {
138             return MessageFormat.format(resources.getString("lf.osc.error.encoding"), e.getMessage());
139         } catch (SocketException e) {
140             return MessageFormat.format(resources.getString("lf.osc.error.socket"), e.getMessage());
141         } catch (IOException e) {
142             return MessageFormat.format(resources.getString("lf.osc.error.io"), e.getMessage());
143         }
144         if (sent) {
145             return resources.getString("lf.osc.success");
146         }
147         return resources.getString("lf.osc.error.invalid");
148     }
149 
150     /**
151      * Convert from String to OSC type.
152      *
153      * @param data the data
154      * @return the object
155      * @throws UnsupportedEncodingException the unsupported encoding exception
156      */
157     private Object convertToOSCType(final String data) throws UnsupportedEncodingException {
158         Object ret = new String(data.getBytes("UTF-8"), Charset.defaultCharset());
159         try {
160             try {
161                 ret = Integer.parseInt(data);
162                 return ret;
163             } catch (NumberFormatException nfe) {
164                 LogUtil.trace(this.getClass(), nfe);
165             }
166 
167             try {
168                 return ret = Float.parseFloat(data);
169             } catch (NumberFormatException nfe) {
170                 LogUtil.trace(this.getClass(), nfe);
171             }
172 
173             return ret;
174         } finally {
175             LogUtil.trace(this.getClass(), MessageFormat.format(resources.getString("lf.osc.type.convert"),
176                     data, ret.getClass().getName()));
177         }
178     }
179 }