/* * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.javame.sensor; import javax.microedition.sensor.*; import java.util.Vector; public class SensorUrl { public static final String SCHEME = "sensor:"; private static final char SEP = ';'; private static final char SEP_PUSH = '?'; private static final char SEP_PUSH2 = '&'; private static final char EQ = '='; private static final String MODEL = "model"; private static final String LOCATION = "location"; private static final String CONTEXT_TYPE = "contextType"; private int numLength; private int currPos; private String parseUrl; private Vector channelList; private String model; private String quantity; private String contextType; private String location; /** Creates a new instance of SensorUrl */ private SensorUrl() { } public String getModel() { return model; } public String getQuantity() { return quantity; } public String getContextType() { return contextType; } public String getLocation() { return location; } private void setModel(String model) { this.model = model; } private void setQuantity(String quantity) { this.quantity = quantity; } private void setContextType(String contextType) { this.contextType = contextType; } private void setLocation(String location) { this.location = location; } /** * Checks symbol is it alphanum. * * @param symbol the source url * * @return true when symbol is alphanum */ static boolean isAlphaNum(char symbol) { return Character.isDigit(symbol) || Character.isLowerCase(symbol) || Character.isUpperCase(symbol) || isMark(symbol); } /** * Checks symbol is it mark. * * @param symbol the source url * * @return true when symbol is * "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" */ static boolean isMark(char symbol) { char[] symbolsMark = {'-', '_', '.', '!', '~', '*', '\'', '(', ')'}; for (int i = 0; i < symbolsMark.length; i++) { if (symbol == symbolsMark[i]) { return true; } } return false; } /** * Gets the alphanum word by current position. * * @return alphanum ID by position * @throws IllegaArgumentException when current * symbol is not alphanum or position is out of string */ private String getId() throws IllegalArgumentException { if (currPos < 0 || currPos > parseUrl.length() - 1) { throw new IllegalArgumentException("Wrong position"); } if (!isAlphaNum(parseUrl.charAt(currPos))) { throw new IllegalArgumentException("First symbol is not alphanum"); } StringBuffer sb = new StringBuffer(); int urlLength = parseUrl.length(); char sym; while (currPos < urlLength && isAlphaNum(sym = parseUrl.charAt(currPos))) { sb.append(sym); currPos++; } return sb.toString(); } /** * Gets the alphanum word by current position * and compare it with pattern. * * @param pattern the word value which getting word should be equal * * @throws IllegaArgumentException when current * symbol is not alphanum or position is out of string or * word is not match */ private void idCompare(String pattern) throws IllegalArgumentException { if (!pattern.equals(getId())) { throw new IllegalArgumentException( "Current word isn't equal to "+pattern); } } /** * Gets the alphanum word by current position * and find it in the pattern array. * * @param patternArray the word value array which getting word * should be find * * @return alphanum ID by position * @throws IllegaArgumentException when current * symbol is not alphanum or position is out of string or * word is not found in the input array */ private String idCompareArr(String[] patterns) throws IllegalArgumentException { String currWord = getId(); boolean isFound = false; for (int i = 0; i < patterns.length; i++) { if (currWord.equals(patterns[i])) { isFound = true; break; } } if (!isFound) { throw new IllegalArgumentException( "Current word isn't found in the input array"); } return currWord; } /** * Gets the double value by current position. * * @return double value by position * @throws IllegaArgumentException on wrong digital format */ private double getNumber() throws IllegalArgumentException { numLength = 0; boolean isFirstPosition = true; boolean isPoint = false; boolean isDigit = false; StringBuffer sb = new StringBuffer(); char currSym; while (currPos < parseUrl.length()) { currSym = parseUrl.charAt(currPos++); if (isFirstPosition) { isFirstPosition = false; if (currSym == '-') { sb.append(currSym); continue; } } if (currSym == '.') { if (!isDigit || isPoint) { throw new IllegalArgumentException( "Wrong decimal point position"); } isPoint = true; sb.append(currSym); } else if (Character.isDigit(currSym)) { sb.append(currSym); isDigit = true; } else { currPos--; break; } } if (!isDigit) { throw new IllegalArgumentException( "Wrong number format"); } numLength = sb.length(); return Double.parseDouble(sb.toString()); } /** * Checks that current symbol is a separator. * * @param separator symbol of separator * * @throws IllegalArgumentException when current symbol is not separator or * position is wrong */ private void checkSeparator(char separator) throws IllegalArgumentException { if (currPos < 0 || currPos > parseUrl.length() - 1) { throw new IllegalArgumentException("Wrong position"); } if (separator != parseUrl.charAt(currPos++)) { throw new IllegalArgumentException("Current symbol is not separator "+ "url = \""+parseUrl+"\" pos = "+currPos); } } /** * Parse sensor URL for Connector.open(). * * @param url the source url * @return SensorUrl object * @throws IllegaArgumentException when url is not valid */ public static SensorUrl parseUrl(String url) { SensorUrl su = new SensorUrl(); su.parseUrl = new String(url); // <sensor_url> ::= "sensor:"<sensor_id> if (!su.parseUrl.startsWith(SCHEME)) { throw new IllegalArgumentException("Wrong scheme"); } su.currPos = SCHEME.length(); int urlLength = su.parseUrl.length(); // <sensor_id> ::= <quantity>[<contextType>][<model>][<location>] // <quantity> ::= ("temperature"|"acceleration"|...) String quantity = su.getId(); su.setQuantity(quantity); boolean isContentType = false; boolean isModel = false; boolean isLocation = false; while (su.currPos < urlLength) { // contextType, model, location start with separator su.checkSeparator(SEP); // <contextType> ::= <separator>"contextType="("ambient"|"device"|"user") // <model> ::= <separator>"model="<model_id> // <location> ::= <separator>"location="<location_id> String[] headers = {CONTEXT_TYPE, MODEL, LOCATION}; String header = su.idCompareArr(headers); su.checkSeparator(EQ); if (header.equals(CONTEXT_TYPE)) { if (isContentType) { throw new IllegalArgumentException( "contextType defined twice"); } isContentType = true; String[] headers1 = {SensorInfo.CONTEXT_TYPE_AMBIENT, SensorInfo.CONTEXT_TYPE_DEVICE, SensorInfo.CONTEXT_TYPE_USER}; String contextTypeValue = su.idCompareArr(headers1); su.setContextType(contextTypeValue); } else if (header.equals(MODEL)) { // <model> ::= <separator>"model="<model_id> // <model_id> ::= <alphanum>* if (isModel) { throw new IllegalArgumentException("model defined twice"); } isModel = true; String modelId = su.getId(); su.setModel(modelId); } else if (header.equals(LOCATION)) { // <location> ::= <separator>"location="<location_id> // <location_id> ::= <alphanum>* if (isLocation) { throw new IllegalArgumentException("location defined twice"); } isLocation = true; String locationId = su.getId(); su.setLocation(locationId); } } return su; } /** * Parse sensor URL for push registration. * * @param url the source url * @return SensorUrl object * @throws IllegaArgumentException when url is not valid */ public static SensorUrl parseUrlPush(String url) { // <push_sensor_url> ::= <sensor_url>[<params>] // <params> ::= "?"<channel_list> int i = url.indexOf(SEP_PUSH); if (i == -1) { return parseUrl(url); } SensorUrl su = parseUrl(url.substring(0, i)); su.parseUrl = new String(url.substring(i + 1)); su.currPos = 0; int savePos; int urlLength = su.parseUrl.length(); if (su.currPos > urlLength - 1) { throw new IllegalArgumentException("No channel list"); } // parse channel list while (su.currPos < urlLength) { // <channel_list> ::= <channel>[<separator2><channel>]* // <channel> ::= "channel="<channel_id><separator2><condition_list> su.idCompare("channel"); su.checkSeparator(EQ); String channelId = su.getId(); if (su.channelList == null) { su.channelList = new Vector(); } su.checkSeparator(SEP_PUSH2); Vector conditionList = new Vector(); // fill condition list su.currPos--; while (su.currPos < urlLength && su.parseUrl.charAt(su.currPos) == SEP_PUSH2) { su.currPos++; // <condition_list> ::= <condition>[<separator2><condition>]* // <condition> ::= (<limit>|<range>) // <limit> ::= // "limit="<double><separator2>"op="("eq"|"lt"|"le"|"ge"|"gt") // <double>::= "-"?(<integer>|<decimal>) // <integer> ::= <nonzero-digit><digit>* // <decimal> ::= <integer>"."<digit>+ savePos = su.currPos; String[] headers = {"limit", "lowerLimit", "channel"}; String conditionName = su.idCompareArr(headers); // next header could be "channel" if (conditionName.equals("channel")) { if (conditionList.size() > 0) { // goto parsing new channel su.currPos = savePos; break; } else { throw new IllegalArgumentException("No condition list"); } } su.checkSeparator(EQ); if (conditionName.equals("limit")) { // limit condition double limit = su.getNumber(); su.checkSeparator(SEP_PUSH2); su.idCompare("op"); su.checkSeparator(EQ); String[] opValues = {Condition.OP_EQUALS, Condition.OP_GREATER_THAN, Condition.OP_GREATER_THAN_OR_EQUALS, Condition.OP_LESS_THAN, Condition.OP_LESS_THAN_OR_EQUALS}; String opValue = su.idCompareArr(opValues); conditionList.addElement(new LimitCondition(limit, opValue)); } else if(conditionName.equals("lowerLimit")) { // range condition // <range>::= "lowerLimit="<double><separator2> // "lowerOp="("ge"|"gt")<separator2> // "upperLimit="<double><separator2> "upperOp="("le"|"lt") double lowerLimit = su.getNumber(); su.checkSeparator(SEP_PUSH2); su.idCompare("lowerOp"); su.checkSeparator(EQ); String[] headers1 = {Condition.OP_GREATER_THAN, Condition.OP_GREATER_THAN_OR_EQUALS}; String lowerOpValue = su.idCompareArr(headers1); su.checkSeparator(SEP_PUSH2); su.idCompare("upperLimit"); su.checkSeparator(EQ); double upperLimit = su.getNumber(); su.checkSeparator(SEP_PUSH2); su.idCompare("upperOp"); su.checkSeparator(EQ); String[] headers2 = {Condition.OP_LESS_THAN, Condition.OP_LESS_THAN_OR_EQUALS}; String upperOpValue = su.idCompareArr(headers2); conditionList.addElement(new RangeCondition( lowerLimit, lowerOpValue, upperLimit, upperOpValue)); } } Object[] arr = {channelId, conditionList}; su.channelList.addElement(arr); } return su; } public static String createUrl(SensorInfo info) { StringBuffer b = new StringBuffer(SCHEME); b.append(info.getQuantity()); if (info.getContextType() != null) { b.append(SEP); b.append(CONTEXT_TYPE); b.append(EQ); b.append(info.getContextType()); } if (info.getModel() != null) { b.append(SEP); b.append(MODEL); b.append(EQ); b.append(info.getModel()); } String loc = null; try { loc = (String)info.getProperty(SensorInfo.PROP_LOCATION); } catch (IllegalArgumentException ex) { } if (loc != null) { b.append(SEP); b.append(LOCATION); b.append(EQ); b.append(loc); } return b.toString(); } }