001/** 002 * Copyright (c) 2012, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.twitter; 031 032import java.io.DataInput; 033import java.io.DataOutput; 034import java.io.IOException; 035import java.io.PrintWriter; 036import java.lang.reflect.Field; 037import java.util.ArrayList; 038import java.util.HashMap; 039import java.util.List; 040import java.util.Map; 041 042import org.openimaj.io.ReadWriteable; 043 044import com.google.gson.Gson; 045import com.google.gson.GsonBuilder; 046 047/** 048 * This interface should be implemented by classes that will define a new json 049 * input format for the USMFStatus object. This object will be populated by GSon 050 * which fills the fields of the object with the matching named values in a json 051 * string structure. It is up to the extending programmer to implement their 052 * object so that it is accurately filled by GSon. See more here 053 * http://code.google.com/p/google-gson/ 054 * 055 * @author Laurence Willmore <lgw1e10@ecs.soton.ac.uk> 056 * 057 */ 058public abstract class GeneralJSON implements ReadWriteable { 059 060 protected transient static Gson gson = new GsonBuilder().serializeNulls().create(); 061 062 /** 063 * This is the method that will be called by USMFStatus to fill itself with 064 * the matching values from the extending class. 065 * It is up to the extending programmer to carry this out as they see fit. 066 * See GeneralJSONTwitter for a Twitter example. 067 * 068 * @param status 069 * = USMFStatus to be filled 070 */ 071 public abstract void fillUSMF(USMFStatus status); 072 073 /** 074 * This is the method that will be called to allow this object 075 * to fill itself from a USMF object. Implementations must guarantee 076 * that they hold on and copy internal ANALYSIS. we recommend the 077 * helper function 078 * 079 * @param status 080 * = USMFStatus to be filled 081 */ 082 public abstract void fromUSMF(USMFStatus status); 083 084 @Override 085 public void readBinary(DataInput in) throws IOException { 086 throw new UnsupportedOperationException(); 087 } 088 089 @Override 090 public byte[] binaryHeader() { 091 return "BINARYHEADER".getBytes(); 092 } 093 094 @Override 095 public void writeBinary(DataOutput out) throws IOException { 096 throw new UnsupportedOperationException(); 097 098 } 099 100 @Override 101 public String asciiHeader() { 102 return ""; 103 } 104 105 @Override 106 public void writeASCII(PrintWriter out) throws IOException { 107 108 writeASCIIAnalysis(out, null, null); 109 } 110 111 /** 112 * analysos held in the object 113 */ 114 public Map<String, Object> analysis = new HashMap<String, Object>(); 115 116 /** 117 * Convenience to allow writing of just the analysis to a writer 118 * 119 * @param outputWriter 120 * @param selectiveAnalysis 121 */ 122 public void writeASCIIAnalysis(PrintWriter outputWriter, List<String> selectiveAnalysis) { 123 writeASCIIAnalysis(outputWriter, selectiveAnalysis, new ArrayList<String>()); 124 } 125 126 /** 127 * Convenience to allow writing of just the analysis and some status 128 * information to a writer 129 * 130 * @param outputWriter 131 * @param selectiveAnalysis 132 * @param selectiveStatus 133 */ 134 public void writeASCIIAnalysis(PrintWriter outputWriter, List<String> selectiveAnalysis, List<String> selectiveStatus) { 135 Map<String, Object> toOutput = new HashMap<String, Object>(); 136 if (selectiveAnalysis == null && selectiveStatus == null) { 137 gson.toJson(this, outputWriter); 138 return; 139 } 140 Map<String, Object> analysisBit = new HashMap<String, Object>(); 141 toOutput.put("analysis", analysisBit); 142 for (String analysisKey : selectiveAnalysis) { 143 analysisBit.put(analysisKey, getAnalysis(analysisKey)); 144 } 145 for (String status : selectiveStatus) { 146 try { 147 148 Field f = this.getClass().getField(status); 149 toOutput.put(status, f.get(this)); 150 } catch (SecurityException e) { 151 System.err.println("Invalid field: " + status); 152 } catch (NoSuchFieldException e) { 153 System.err.println("Invalid field: " + status); 154 } catch (IllegalArgumentException e) { 155 System.err.println("Invalid field: " + status); 156 } catch (IllegalAccessException e) { 157 System.err.println("Invalid field: " + status); 158 } 159 } 160 gson.toJson(toOutput, outputWriter); 161 } 162 163 /** 164 * Add analysis to the analysis object. This is where all non twitter stuff 165 * should go 166 * 167 * @param <T> 168 * The type of data being saved 169 * @param annKey 170 * the key 171 * @param annVal 172 * the value 173 */ 174 public <T> void addAnalysis(String annKey, T annVal) { 175 if (annVal instanceof Number) 176 this.analysis.put(annKey, ((Number) annVal).doubleValue()); 177 else 178 this.analysis.put(annKey, annVal); 179 } 180 181 /** 182 * @param <T> 183 * @param name 184 * @return the analysis under the name 185 */ 186 @SuppressWarnings("unchecked") 187 public <T> T getAnalysis(String name) { 188 return (T) this.analysis.get(name); 189 } 190 191 /** 192 * Get all the Analysis in JSON format. 193 * 194 * @return String of JSON. 195 */ 196 public String analysisToJSON() { 197 return gson.toJson(analysis, Map.class); 198 } 199 200 /** 201 * @param other 202 */ 203 public void fillAnalysis(GeneralJSON other) { 204 other.analysis = this.analysis; 205 } 206 207 /** 208 * @param line 209 * @return construct an instance of this type from a string 210 */ 211 public abstract GeneralJSON instanceFromString(String line); 212 213}