You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devicemap.apache.org by re...@apache.org on 2014/07/04 22:01:36 UTC

svn commit: r1607924 - in /incubator/devicemap/trunk/devicemap/java/classifier/src: main/ main/java/ main/java/org/ main/java/org/apache/ main/java/org/apache/devicemap/ main/java/org/apache/devicemap/cmd/ main/java/org/apache/devicemap/data/ main/java...

Author: rezan
Date: Fri Jul  4 20:01:35 2014
New Revision: 1607924

URL: http://svn.apache.org/r1607924
Log:
refactored paths

Added:
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Constants.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/DeviceMapClient.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Util.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/cmd/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/cmd/Main.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Device.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Pattern.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/FileLoader.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/JarLoader.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/Loader.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/LoaderFactory.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/NOOPLoader.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/ResourceLoader.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/URLLoader.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/parser/
    incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/parser/XMLParser.java
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/client/
    incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/client/DeviceMapClientTest.java

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Constants.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Constants.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Constants.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Constants.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,30 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class Constants {
+    
+    public static final String version="0.9";
+    
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/DeviceMapClient.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/DeviceMapClient.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/DeviceMapClient.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/DeviceMapClient.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,153 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap;
+
+import org.apache.devicemap.data.Device;
+import org.apache.devicemap.loaders.LoaderFactory;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author Reza Naghibi
+ * @author Werner Keil
+ */
+public class DeviceMapClient {
+    
+    //indexes
+    Map<String,Device> devices;
+    final Map<String,List<Device>> patterns;
+    
+    public DeviceMapClient() {
+        devices=new HashMap<String,Device>();
+        patterns=new HashMap<String,List<Device>>();
+    }
+
+    public void loadFromResource(String option, String res) throws IOException{
+        devices = LoaderFactory.getLoader(option).getData(res);
+        createIndex();
+    }
+    
+    //load DDR indexes from a folder
+    public void loadFromFolder(String folder) throws IOException {
+        devices=LoaderFactory.getLoader("-l").getData(folder);
+        
+        createIndex();
+    }
+    
+    private void createIndex() {
+        for(Device device:devices.values()) {
+            for(List<String> patternset:device.getPatterns().getPatterns()) {
+                for(int i=0;i<patternset.size();i++) {
+                    String pattern=patternset.get(i);
+                    
+                    //duplicate
+                    if(patterns.get(pattern)!=null) {
+                        if(i==(patternset.size()-1) && !patterns.get(pattern).contains(device)) {
+                            patterns.get(pattern).add(device);
+                        }
+                    } else {
+                        List<Device> single=new ArrayList<Device>();
+                        single.add(device);
+                        patterns.put(pattern, single);
+                    }
+                }
+            }
+        }
+    }
+    
+    public Map<String,String> classify(String text) {
+        Map<String,List<Device>> hits=new HashMap<String,List<Device>>();
+        Device winner=null;
+        String winnerStr="";
+        
+        if(text==null) {
+            return null;
+        }
+        
+        Util.debugLog("classify: '"+text+"'");
+        
+        String[] parts=text.split(" |-|_|/|\\\\|\\[|\\]|\\(|\\)|;");
+        
+        //generate ngrams upto size 4
+        for(int i=0;i<parts.length;i++) {
+            if(parts[i].isEmpty()) {
+                continue;
+            }
+            String pattern="";
+            for(int j=0;j<4 && (j+i)<parts.length;j++) {
+                pattern+=Util.normalize(parts[i+j]);
+                
+                List<Device> dlist=patterns.get(pattern);
+                
+                if(dlist!=null) {
+                    hits.put(pattern, dlist);
+                    
+                    for(Device device:dlist) {
+                        Util.debugLog("Hit found: "+pattern+" => "+device.getId()+" "+device.getPatterns());
+                    }
+                }
+            }
+        }
+        
+        //look for the strongest hit
+        for(String hit:hits.keySet()) {
+            for(Device device:hits.get(hit)) {
+                if(!device.getPatterns().isValid(hits.keySet())) {
+                    continue;
+                }
+
+                Util.debugLog("Hit candidate: "+hit+" => "+device.getId());
+
+                if(winner!=null) {
+                    if("simple".equals(winner.getType()) && !"simple".equals(device.getType())) {
+                        winner=device;
+                        winnerStr=hit;
+                    } else if(hit.length()>winnerStr.length() && !"simple".equals(device.getType())) {
+                        winner=device;
+                        winnerStr=hit;
+                    }
+                } else {
+                    winner=device;
+                    winnerStr=hit;
+                }
+            }
+        }
+        
+        if(winner!=null) {
+            Util.debugLog("Result: "+winner);
+            
+            return winner.getAttributes();
+        } else {
+            return null;
+        }
+    }
+    
+    public int getDeviceCount() {
+        return devices.size();
+    }
+
+    public int getPatternCount() {
+        return patterns.size();
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Util.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Util.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Util.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/Util.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,72 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class Util {
+    
+    /*
+     * normalizes a pattern
+     */
+    public static String normalize(String p) {
+        if(p==null) {
+            return p;
+        }
+        
+        p=p.toLowerCase().trim();
+        
+        p=p.replaceAll("\\[bb\\]","b");
+        
+        StringBuilder ret=new StringBuilder();
+        
+        for(int i=0;i<p.length();i++) {
+            Character c=p.charAt(i);
+            if(Character.isLetter(c) || Character.isDigit(c)) {
+                ret.append(c);
+            }
+        }
+        
+        return ret.toString();
+    }
+    
+    public static void debugLog(String msg) {
+        debugLog(msg, null);
+    }
+    
+    public static void debugLog(String msg, Exception e) {
+        if(System.getProperty("debug") == null) {
+            return;
+        }
+        
+        String date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS").format(new Date());
+        
+        System.out.println(date+" [dmapjclient] "+msg);
+        
+        if(e!=null) {
+            e.printStackTrace();
+        }
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/cmd/Main.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/cmd/Main.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/cmd/Main.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/cmd/Main.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,155 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap.cmd;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.Map;
+import org.apache.devicemap.Constants;
+import org.apache.devicemap.DeviceMapClient;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class Main {
+    
+    public static void main(String[] args) throws Exception {
+        
+        System.out.println("DeviceMap Java Client "+Constants.version);
+        
+        System.setProperty("debug","true");
+        
+        String resourceFolder=null;
+        String parameter=null;
+        String option=null;
+        
+        for(int i=0;i<args.length;i++)
+        {
+            //-l [resource folder]
+            if((args[i].equals("-l") || args[i].equals("-u")) && args.length>(i+1)) {
+                option=args[i];
+                i++;
+                resourceFolder=args[i];
+            } else if(args[i].equals("-j")) {
+                option=args[i];
+                resourceFolder="";
+            } else if(args[i].startsWith("-h") || args[i].startsWith("--h")) {
+                System.out.println("Usage: "+Main.class.getName()+" [OPTIONS] [FILE|STRING]\n");
+                System.out.println("  -l <path>            load Device Map resouces from folder");
+                System.out.println("  -j                   load Device Map resouces from jar file in classpath");
+                System.out.println("  -u <url>             load Device Map resouces from URL");
+                System.out.println("  FILE                 text file of strings");
+                System.out.println("  STRING               test string");
+                
+                return;
+            }
+            //[test string] | [test file]
+            else
+                parameter=args[i];
+        }
+        
+        DeviceMapClient client=new DeviceMapClient();
+        Map<String,String> m;
+        
+        if(option!=null && !option.isEmpty()) {
+            long start=System.currentTimeMillis();
+            
+            client.loadFromResource(option,resourceFolder);
+            
+            long diff=System.currentTimeMillis()-start;
+            
+            System.out.println("Loaded "+client.getDeviceCount()+" devices with "+client.getPatternCount()+" patterns in "+diff+"ms");
+        }
+        
+        String test="Mozilla/5.0 (Linux; U; Android 2.2; en; HTC Aria A6380 Build/ERE27) AppleWebKit/540.13+ (KHTML, like Gecko) Version/3.1 Mobile Safari/524.15.0";
+
+        long startn=System.nanoTime();
+
+        m=client.classify(test);
+
+        long diffn=(System.nanoTime()-startn)/1000;
+
+        System.out.println("Test lookup: '"+(m!=null?m.get("id"):"unknown")+"' time: "+diffn+"usec");
+        
+        if(parameter==null);
+        else if((new File(parameter)).exists())
+        {
+            System.out.println("Text file: "+parameter);
+
+            int count=0;
+            int total=0;
+
+            BufferedReader in=new BufferedReader(new FileReader(parameter));
+            String line;
+
+            while((line=in.readLine())!=null)
+            {
+                System.out.println("Text: '"+line+"'");
+
+                startn=System.nanoTime();
+
+                m=client.classify(line);
+
+                diffn=System.nanoTime()-startn;
+
+                total+=diffn;
+                count++;
+
+                System.out.println("Text lookup "+count+": '"+(m!=null?m.get("id"):"unknown")+"' time: "+(diffn/1000)+"usec");
+            }
+
+            in.close();
+            
+            if(count==0) {
+                count=1;
+            }
+
+            total/=count; 
+
+            System.out.println("TOTAL lookups: "+count+", average time: "+(diffn/1000)+"usec");
+        }
+        else
+        {
+            System.out.println("Text: '"+parameter+"'");
+
+            startn=System.nanoTime();
+
+            m=client.classify(parameter);
+
+            diffn=System.nanoTime()-startn;
+
+            System.out.println("Text lookup: '"+(m!=null?m.get("id"):"unknown")+"' time: "+(diffn/1000)+"usec");
+
+            if(m!=null) {
+                System.out.print("DeviceMap attributes => ");
+
+                for(String key:m.keySet())
+                {
+                    String value=m.get(key);
+                    System.out.print(key+": '"+value+"' ");
+                }
+
+                System.out.println("");
+            }
+        }
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Device.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Device.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Device.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Device.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,87 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap.data;
+
+import java.util.Map;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class Device {
+    
+    private String id;
+    
+    private String parentId;
+    
+    private String type;
+    
+    private Pattern pattern;
+    
+    private Map<String,String> attributes;
+    
+    public Device() {
+        pattern=new Pattern();
+    }
+    
+    public String toString() {
+        return "id='"+id+"'," +
+               "parentId='"+parentId+"',"+
+               "type='"+type+"',"+
+               "pattern="+pattern+","+
+               "attribytes="+attributes+".";
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Pattern getPatterns() {
+        return pattern;
+    }
+
+    public Map<String,String> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String,String> attributes) {
+        this.attributes = attributes;
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Pattern.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Pattern.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Pattern.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/data/Pattern.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,92 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class Pattern {
+    
+    //all patterns strings in the inner list need to match (AND)
+    //only 1 outer list of patterns need to match (OR)
+    private List<List<String>> patterns;
+    
+    public Pattern() {
+        patterns=new ArrayList<List<String>>();
+    }
+    
+    public String toString() {
+        return patterns.toString();
+    }
+    
+    /*
+     * add the patterns together as an inner list (AND)
+     */
+    public void setAndPattern(List<String> patterns) {
+        this.patterns.add(patterns);
+    }
+    
+    /*
+     * add each pattern on its own list (OR)
+     */
+    public void setOrPattern(List<String> patterns) {
+        for(String pattern:patterns) {
+            setPattern(pattern);
+        }
+    }
+    
+    /*
+     * add a single pattern (OR)
+     */
+    public void setPattern(String pattern) {
+        List<String> single=new ArrayList<String>();
+        single.add(pattern);
+        patterns.add(single);
+    }
+    
+    public List<List<String>> getPatterns() {
+        return patterns;
+    }
+    
+    /*
+     * does the set of patterns match this object?
+     */
+    public boolean isValid(Set<String> patterns) {
+        boolean found=false;
+        patterns:
+        for(List<String> patternset:getPatterns()) {
+            for(String pattern:patternset) {
+                if(!patterns.contains(pattern)) {
+                    continue patterns;
+                }
+            }
+            found=true;
+            break;
+        }
+        
+        return found;
+    }
+
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/FileLoader.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/FileLoader.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/FileLoader.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/FileLoader.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,109 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap.loaders;
+
+import org.apache.devicemap.loaders.Loader;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Map;
+import org.apache.devicemap.data.Device;
+import org.apache.devicemap.Util;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class FileLoader implements ResourceLoader{
+    
+    private final Loader loader;
+    
+    
+    public FileLoader(Loader loader){
+        this.loader = loader;
+    }
+    
+    /**
+     * 
+     * @param folder which contains device map data
+     * @return map of devices
+     * @throws IOException 
+     */
+    public  Map<String,Device> getData(String folder) throws IOException {
+       
+        
+        String ddpath=folder+File.separatorChar+"DeviceDataSource.xml";
+        String ddppath=folder+File.separatorChar+"DeviceDataSourcePatch.xml";
+        String bpath=folder+File.separatorChar+"BuilderDataSource.xml";
+        String bppath=folder+File.separatorChar+"BuilderDataSourcePatch.xml";
+
+        long start=System.currentTimeMillis();
+        
+        BufferedReader ddin=new BufferedReader(new InputStreamReader(new FileInputStream(ddpath), "UTF-8"));
+        loader.loadDeviceData(ddin);
+        ddin.close();
+        
+        long diff=System.currentTimeMillis()-start;
+        Util.debugLog("Loaded "+ddpath+" in "+diff+"ms");
+        
+        try {
+            start=System.currentTimeMillis();
+            
+            BufferedReader ddpin=new BufferedReader(new InputStreamReader(new FileInputStream(ddppath), "UTF-8"));
+            loader.loadDeviceData(ddpin);
+            ddpin.close();
+            
+            diff=System.currentTimeMillis()-start;
+            Util.debugLog("Loaded "+ddppath+" in "+diff+"ms");
+        } catch(FileNotFoundException ex) {
+            Util.debugLog("WARNING: file not found "+ddppath+": "+ex.toString());
+        }
+
+        loader.setParentAttributes();
+
+        start=System.currentTimeMillis();
+        
+        BufferedReader bin=new BufferedReader(new InputStreamReader(new FileInputStream(bpath), "UTF-8"));
+        loader.loadDevicePatterns(bin);
+        bin.close();
+        
+        diff=System.currentTimeMillis()-start;
+        Util.debugLog("Loaded "+bpath+" in "+diff+"ms");
+        
+        try {
+            start=System.currentTimeMillis();
+            
+            BufferedReader bpin=new BufferedReader(new InputStreamReader(new FileInputStream(bppath), "UTF-8"));
+            loader.loadDevicePatterns(bpin);
+            bpin.close();
+            
+            diff=System.currentTimeMillis()-start;
+            Util.debugLog("Loaded "+bppath+" in "+diff+"ms");
+        } catch(FileNotFoundException ex) {
+            Util.debugLog("WARNING: file not found "+bppath+": "+ex.toString());
+        }
+
+        return loader.getDevices();
+    }
+
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/JarLoader.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/JarLoader.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/JarLoader.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/JarLoader.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,100 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+package org.apache.devicemap.loaders;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Map;
+
+import org.apache.devicemap.Util;
+import org.apache.devicemap.data.Device;
+
+/**
+ *
+ * @author kalyanar
+ * @author Reza Naghibi
+ */
+public class JarLoader implements ResourceLoader {
+
+    private final Loader loader;
+
+    public JarLoader(Loader loader) {
+        this.loader = loader;
+    }
+
+    @Override
+    public Map<String, Device> getData(String path) throws IOException {
+        if(path==null) {
+            path="";
+        }
+        
+        String ddpath = path+"/devicedata/DeviceDataSource.xml";
+        String ddppath = path+"/devicedata/DeviceDataSourcePatch.xml";
+        String bpath = path+"/devicedata/BuilderDataSource.xml";
+        String bppath = path+"/devicedata/BuilderDataSourcePatch.xml";
+
+        long start = System.currentTimeMillis();
+        BufferedReader ddin = new BufferedReader(new InputStreamReader(JarLoader.class.getResourceAsStream(ddpath), "UTF-8"));
+        loader.loadDeviceData(ddin);
+        ddin.close();
+
+        long diff = System.currentTimeMillis() - start;
+        Util.debugLog("Loaded " + ddpath + " in " + diff + "ms");
+        try {
+            start = System.currentTimeMillis();
+
+            BufferedReader ddpin = new BufferedReader(new InputStreamReader(JarLoader.class.getResourceAsStream(ddppath), "UTF-8"));
+            loader.loadDeviceData(ddpin);
+            ddpin.close();
+
+            diff = System.currentTimeMillis() - start;
+            Util.debugLog("Loaded " + ddppath + " in " + diff + "ms");
+        } catch (FileNotFoundException ex) {
+            Util.debugLog("WARNING: file not found " + ddppath + ": " + ex.toString());
+        }
+
+        loader.setParentAttributes();
+
+        start = System.currentTimeMillis();
+
+        BufferedReader bin = new BufferedReader(new InputStreamReader(JarLoader.class.getResourceAsStream(bpath), "UTF-8"));
+        loader.loadDevicePatterns(bin);
+        bin.close();
+
+        diff = System.currentTimeMillis() - start;
+        Util.debugLog("Loaded " + bpath + " in " + diff + "ms");
+
+        try {
+            start = System.currentTimeMillis();
+
+            BufferedReader bpin = new BufferedReader(new InputStreamReader(JarLoader.class.getResourceAsStream(bppath), "UTF-8"));
+            loader.loadDevicePatterns(bpin);
+            bpin.close();
+
+            diff = System.currentTimeMillis() - start;
+            Util.debugLog("Loaded " + bppath + " in " + diff + "ms");
+        } catch (FileNotFoundException ex) {
+            Util.debugLog("WARNING: file not found " + bppath + ": " + ex.toString());
+        }
+
+        return loader.getDevices();
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/Loader.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/Loader.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/Loader.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/Loader.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,198 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap.loaders;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.devicemap.data.Device;
+import org.apache.devicemap.Util;
+import org.apache.devicemap.parser.XMLParser;
+
+/**
+ *
+ * @author Reza Naghibi
+ */
+public class Loader {
+    
+    private Map<String,Device> devices;
+    
+    public Loader() {
+        devices=new HashMap<String,Device>();
+    }
+    
+    /*
+     * loads device data from an InputStreamReader
+     */
+    public void loadDeviceData(Reader in) {
+        XMLParser parser=new XMLParser(in);
+        String tag;
+        
+        try {
+            Device device=new Device();
+            Map<String,String> attributes=new HashMap<String,String>();
+            
+            while(!(tag=parser.getNextTag()).isEmpty()) {
+                //new device found
+                if(tag.startsWith("<device ")) {
+                    device.setId(XMLParser.getAttribute(tag,"id"));
+                    device.setParentId(XMLParser.getAttribute(tag,"parentId"));
+                } else if(tag.equals("</device>")) {
+                    
+                    //add the device
+                    if(device.getId()!=null && !device.getId().isEmpty()) {
+                        attributes.put("id", device.getId());
+                        device.setAttributes(attributes);
+                        devices.put(device.getId(), device);
+                    }
+                    
+                    //reset the device
+                    device=new Device();
+                    attributes=new HashMap<String,String>();
+                } else if(tag.startsWith("<property ")) {
+                    //add the property to the device
+                    String key=XMLParser.getAttribute(tag,"name");
+                    String value=XMLParser.getAttribute(tag,"value");
+                    
+                    attributes.put(key,value);
+                }
+            }
+        } catch(Exception ex) {
+            Util.debugLog("ERROR: "+ex.toString(),ex);
+        }
+    }
+    
+    /*
+     * loads patterns from an InputStreamReader
+     */
+    public void loadDevicePatterns(Reader in) {
+        XMLParser parser=new XMLParser(in);
+        String tag;
+        
+        try {
+            String builder="";
+            Device device=null;
+            String id="";
+            List<String> patterns=new ArrayList<String>();
+            
+            while(!(tag=parser.getNextTag()).isEmpty()) {
+                //new builder found
+                if(tag.startsWith("<builder ")) {
+                    builder=XMLParser.getAttribute(tag,"class");
+                    
+                    if(builder.lastIndexOf(".")>=0) {
+                        builder=builder.substring(builder.lastIndexOf(".")+1);
+                    }
+                } else if(tag.startsWith("<device ")) {
+                    //new device found
+                    device=devices.get(XMLParser.getAttribute(tag,"id"));
+                } else if(tag.equals("</device>")) {
+                    //add the device
+                    if(device!=null) {
+                        //TwoStep is an AND pattern, also index the unigram
+                        if(builder.equals("TwoStepDeviceBuilder")) {
+                            device.getPatterns().setAndPattern(patterns);
+                            
+                            String unigram="";
+                            
+                            for(String pattern:patterns) {
+                                if(pattern.contains(unigram)) {
+                                    unigram=pattern;
+                                } else {
+                                    unigram+=pattern;
+                                }
+                            }
+                            
+                            device.getPatterns().setPattern(unigram);
+                        } else {
+                            device.getPatterns().setOrPattern(patterns);
+                        }
+                        
+                        if(builder.equals("SimpleDeviceBuilder")) {
+                            device.setType("simple");
+                        } else {
+                            device.setType("weak");
+                        }
+                    } else {
+                        Util.debugLog("ERROR: device not found: '"+id+"'");
+                    }
+                    
+                    //reset the device
+                    device=null;
+                    id="";
+                    patterns=new ArrayList<String>();
+                } else if(tag.equals("<value>")) {
+                    //add the pattern to the device
+                    String pattern=Util.normalize(parser.getTagValue());
+                    
+                    if(pattern.isEmpty()) {
+                        continue;
+                    }
+                    
+                    patterns.add(pattern);
+                }
+            }
+        } catch(Exception ex) {
+            Util.debugLog("ERROR: "+ex.toString(),ex);
+        }
+    }
+    
+    /**
+     * Sets attributes from parents
+     */
+    public void setParentAttributes() {
+        for(Device device:devices.values()) {
+            mergeParent(device);
+        }
+    }
+    
+    private void mergeParent(Device device) {
+        String parentId=device.getParentId();
+        
+        if(parentId==null) {
+            return;
+        }
+        
+        Device parent=devices.get(parentId);
+        
+        if(parent==null) {
+            return;
+        }
+        
+        mergeParent(parent);
+        
+        for(String key:parent.getAttributes().keySet()) {
+            String value=parent.getAttributes().get(key);
+            
+            if(!device.getAttributes().containsKey(key)) {
+                device.getAttributes().put(key, value);
+            }
+        }
+    }
+
+    /**
+     * @return the devices
+     */
+    public Map<String,Device> getDevices() {
+        return devices;
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/LoaderFactory.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/LoaderFactory.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/LoaderFactory.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/LoaderFactory.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,60 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+package org.apache.devicemap.loaders;
+
+public class LoaderFactory {
+    private static  enum LoaderOption{
+       JAR("-j"),FOLDER("-l"),URL("-u"),NOOP("-n");
+    private String loaderType;
+        LoaderOption(String loaderType){
+            this.loaderType = loaderType;
+        }
+        String type(){
+            return this.loaderType;
+        }
+    };
+        
+    
+public static final ResourceLoader getLoader(String option){
+   LoaderOption lOption = getLoaderOption(option);
+   switch(lOption){
+   case JAR:{
+     return new JarLoader(new Loader());  
+   }
+   case FOLDER:{
+       return new FileLoader(new Loader());
+   }
+   case URL:{
+       return new URLLoader(new Loader());
+   }
+   case NOOP:{
+       return new NOOPLoader();
+   }
+   }
+   return new NOOPLoader();
+}
+private static LoaderOption getLoaderOption(String option){
+    for(LoaderOption lOption:LoaderOption.values()){
+        if(lOption.type().equals(option)){
+            return lOption;
+        }
+    }
+    return LoaderOption.NOOP;
+}
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/NOOPLoader.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/NOOPLoader.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/NOOPLoader.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/NOOPLoader.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,17 @@
+package org.apache.devicemap.loaders;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.devicemap.data.Device;
+
+public class NOOPLoader implements ResourceLoader {
+
+    @Override
+    public Map<String, Device> getData(String path) throws IOException {
+        
+        return Collections.emptyMap();
+    }
+
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/ResourceLoader.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/ResourceLoader.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/ResourceLoader.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/ResourceLoader.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,10 @@
+package org.apache.devicemap.loaders;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.devicemap.data.Device;
+
+public interface ResourceLoader {
+    public  Map<String,Device> getData(String path) throws IOException ;
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/URLLoader.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/URLLoader.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/URLLoader.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/loaders/URLLoader.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,84 @@
+package org.apache.devicemap.loaders;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.devicemap.Util;
+import org.apache.devicemap.data.Device;
+/**
+ * 
+ * @author kalyanar
+ * @author Reza Naghibi
+ *
+ */
+public class URLLoader implements ResourceLoader {
+    private final Loader loader;
+    
+    
+    public URLLoader(Loader loader){
+        this.loader = loader;
+    }
+    
+    @Override
+    public Map<String, Device> getData(String path) throws IOException {
+        String ddpath=path+"/DeviceDataSource.xml";
+        String ddppath=path+"/DeviceDataSourcePatch.xml";
+        String bpath=path+"/BuilderDataSource.xml";
+        String bppath=path+"/BuilderDataSourcePatch.xml";
+       long start=System.currentTimeMillis();
+        
+        BufferedReader ddin=new BufferedReader(new InputStreamReader(new URL(ddpath).openStream(), "UTF-8"));
+        loader.loadDeviceData(ddin);
+        ddin.close();
+        
+        long diff=System.currentTimeMillis()-start;
+        Util.debugLog("Loaded "+ddpath+" in "+diff+"ms");
+        
+        try {
+            start=System.currentTimeMillis();
+            
+            BufferedReader ddpin=new BufferedReader(new InputStreamReader(new URL(ddppath).openStream(), "UTF-8"));
+            loader.loadDeviceData(ddpin);
+            ddpin.close();
+            
+            diff=System.currentTimeMillis()-start;
+            Util.debugLog("Loaded "+ddppath+" in "+diff+"ms");
+        } catch(FileNotFoundException ex) {
+            Util.debugLog("WARNING: file not found "+ddppath+": "+ex.toString());
+        }
+
+        loader.setParentAttributes();
+
+        start=System.currentTimeMillis();
+        
+        BufferedReader bin=new BufferedReader(new InputStreamReader(new URL(bpath).openStream(), "UTF-8"));
+        loader.loadDevicePatterns(bin);
+        bin.close();
+        
+        diff=System.currentTimeMillis()-start;
+        Util.debugLog("Loaded "+bpath+" in "+diff+"ms");
+        
+        try {
+            start=System.currentTimeMillis();
+            
+            BufferedReader bpin=new BufferedReader(new InputStreamReader(new URL(bppath).openStream(), "UTF-8"));
+            loader.loadDevicePatterns(bpin);
+            bpin.close();
+            
+            diff=System.currentTimeMillis()-start;
+            Util.debugLog("Loaded "+bppath+" in "+diff+"ms");
+        } catch(FileNotFoundException ex) {
+            Util.debugLog("WARNING: file not found "+bppath+": "+ex.toString());
+        }
+
+        return loader.getDevices();
+
+    }
+
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/parser/XMLParser.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/parser/XMLParser.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/parser/XMLParser.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/main/java/org/apache/devicemap/parser/XMLParser.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,119 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+
+package org.apache.devicemap.parser;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ *
+ * @author Reza Naghibi
+ * @author Werner Keil
+ */
+public class XMLParser {
+    
+    private Reader in;
+    
+    private char pre;
+
+    @SuppressWarnings("unused")
+	private XMLParser() {}
+    
+    public XMLParser(Reader in) {
+        this.in=in;
+        pre=0;
+    }
+    
+    public String getNextTag() throws IOException {
+        StringBuilder ret=new StringBuilder();
+        
+        int i;
+        boolean start=false;
+        
+        if(pre=='<') {
+            ret.append(pre);
+            pre=0;
+            start=true;
+        }
+        
+        while((i=in.read())!=-1) {
+            char c=(char)i;
+            if(c=='<') {
+                start=true;
+                ret.append(c);
+            } else if(c=='>') {
+                ret.append(c);
+                break;
+            } else if(start) {
+                ret.append(c);
+            }
+        }
+        
+        return ret.toString();
+    }
+    
+    public String getTagValue() throws IOException {
+        StringBuilder ret=new StringBuilder();
+        
+        int i;
+        
+        while((i=in.read())!=-1) {
+            char c=(char)i;
+            if(c=='<') {
+                pre='<';
+                break;
+            } else {
+                ret.append(c);
+            }
+        }
+        
+        return ret.toString().trim();
+    }
+    
+    public static String getAttribute(String tag, String name) {
+        int retpos=tag.toLowerCase().indexOf(name.toLowerCase()+"=");
+        
+        if(retpos==-1)
+            return "";
+
+        String ret=tag.substring(retpos+name.length()+1);
+
+        if(ret.startsWith("\"")) {
+            ret=ret.substring(1);
+            int endpos=ret.indexOf("\"");
+            
+            if(endpos==-1) {
+                return "";
+            }
+            
+            ret=ret.substring(0, endpos);
+        } else {
+            int endpos=ret.indexOf(" ");
+            
+            if(endpos==-1) {
+                return "";
+            }
+            
+            ret=ret.substring(0, endpos);
+        }
+        
+        return ret;
+    }
+}

Added: incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/client/DeviceMapClientTest.java
URL: http://svn.apache.org/viewvc/incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/client/DeviceMapClientTest.java?rev=1607924&view=auto
==============================================================================
--- incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/client/DeviceMapClientTest.java (added)
+++ incubator/devicemap/trunk/devicemap/java/classifier/src/test/java/org/apache/devicemap/client/DeviceMapClientTest.java Fri Jul  4 20:01:35 2014
@@ -0,0 +1,43 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+ */
+package org.apache.devicemap.client;
+
+import org.apache.devicemap.DeviceMapClient;
+import java.util.Map;
+import org.junit.Assert;
+import org.junit.Test;
+
+/** 
+ *  
+ */
+public class DeviceMapClientTest {
+    
+    @Test
+    public void DeviceMapClientTest() throws Exception {
+        System.out.println("Testing device map");
+        DeviceMapClient client=new DeviceMapClient();
+        client.loadFromResource("-j","");
+        
+        String test="Mozilla/5.0 (Linux; U; Android 2.2; en; HTC Aria A6380 Build/ERE27) AppleWebKit/540.13+ (KHTML, like Gecko) Version/3.1 Mobile Safari/524.15.0";
+        
+        Map<String,String> m=client.classify(test);
+        
+        Assert.assertEquals("test ua not htc aria", "HTC Aria", m.get("id"));
+    }
+}