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.ByteArrayInputStream; 033import java.io.IOException; 034import java.io.InputStream; 035import java.io.PrintWriter; 036import java.io.StringReader; 037import java.util.ArrayList; 038import java.util.HashMap; 039import java.util.List; 040import java.util.Map; 041import java.util.Scanner; 042 043import org.openimaj.io.FileUtils; 044import org.openimaj.rdf.utils.PQUtils; 045import org.openimaj.twitter.USMFStatus.Link; 046import org.openimaj.twitter.USMFStatus.User; 047import org.openjena.riot.SysRIOT; 048 049import com.hp.hpl.jena.query.ParameterizedSparqlString; 050import com.hp.hpl.jena.rdf.model.Model; 051import com.hp.hpl.jena.rdf.model.ModelFactory; 052import com.hp.hpl.jena.rdf.model.Resource; 053import com.hp.hpl.jena.update.UpdateAction; 054import com.hp.hpl.jena.update.UpdateRequest; 055 056/** 057 * Holds an internal Jena Graph of the USMF status. The default language used is 058 * NTriples 059 * 060 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 061 * 062 */ 063public class GeneralJSONRDF extends GeneralJSON { 064 065 enum Variables { 066 SERVICE("service"), 067 SOCIAL_EVENT("socialEvent"), 068 USER("user"), 069 PERSON("person"), 070 PERSON_NAME("realname"), 071 PERSON_LOC("location"), 072 PERSON_LAT("lat"), 073 PERSON_LONG("long"), 074 USER_NAME("username"), 075 USER_ID("osnid"), 076 USER_LANG("userlanguage"), 077 PERSON_LANG("personlanguage"), 078 USER_DESC("description"), 079 USER_AVATAR("useravatar"), 080 USER_SITE("website"), 081 USER_PROF("profile"), 082 USER_FOLLOWERS("subscribers"), 083 USER_FOLLOWING("subscriptions"), 084 SOURCE_URL("sourceURL"), 085 TEXT("text"), 086 DESC("description"), 087 CAT("category"), 088 FAV("favourites"), 089 USER_POSTS("postings"), LINK("link"), KEYWORD("keyword"), ; 090 public String name; 091 092 private Variables(String name) { 093 this.name = name; 094 } 095 096 } 097 098 // private static final String ITEM_QUERY_FILE = 099 // "/org/openimaj/twitter/rdf/usmf_query.sparql"; 100 private static final String INSERT_ITEM_QUERY_FILE = "/org/openimaj/twitter/rdf/insert_usmf_query.sparql"; 101 private static final String DELETE_TM_NULL = "/org/openimaj/twitter/rdf/delete_null.sparql"; 102 private static final String LINK_INSERT_QUERY_FILE = "/org/openimaj/twitter/rdf/insert_usmf_links_query.sparql"; 103 private static final String KEYWORDS_INSERT_QUERY_FILE = "/org/openimaj/twitter/rdf/insert_usmf_keywords_query.sparql"; 104 private static final String TOUSERS_INSERT_QUERY_FILE = "/org/openimaj/twitter/rdf/insert_usmf_touser_query.sparql";; 105 private static Map<String, String> queryCache; 106 107 static { 108 SysRIOT.wireIntoJena(); 109 } 110 111 private Model m; 112 private Resource eventIRI; 113 private static String baseModelString; 114 static { 115 try { 116 baseModelString = FileUtils.readall(GeneralJSONRDF.class.getResourceAsStream("rdf/base_usmf.rdf")); 117 System.out.println("Read in base model!"); 118 } catch (final IOException e) { 119 120 } 121 } 122 private static final Map<String, RDFAnalysisProvider> providers = new HashMap<String, RDFAnalysisProvider>(); 123 124 /** 125 * Registers an analysis provider to be used when some analysis key is met 126 * 127 * @param analysis 128 * @param analysisProvider 129 */ 130 public static void registerRDFAnalysisProvider(String analysis, RDFAnalysisProvider analysisProvider) { 131 analysisProvider.init(); 132 providers.put(analysis, analysisProvider); 133 } 134 135 @Override 136 public void readASCII(final Scanner in) throws IOException { 137 final StringBuffer b = new StringBuffer(); 138 while (in.hasNext()) { 139 b.append(in.next()); 140 } 141 final InputStream stream = new ByteArrayInputStream(b.toString().getBytes("UTF-8")); 142 m = ModelFactory.createDefaultModel(); 143 m.read(stream, "", "NTRIPLES"); 144 m.close(); 145 } 146 147 @Override 148 public void fillUSMF(USMFStatus status) { 149 throw new UnsupportedOperationException("Not supported yet"); 150 } 151 152 private static String queryCache(String queryFile) { 153 if (queryCache == null) { 154 queryCache = new HashMap<String, String>(); 155 } 156 String q = queryCache.get(queryFile); 157 if (q == null) { 158 queryCache.put(queryFile, q = readQuery(queryFile)); 159 } 160 return q; 161 } 162 163 private static String readQuery(String qf) { 164 try { 165 return FileUtils.readall(GeneralJSONRDF.class.getResourceAsStream(qf)); 166 } catch (final IOException e) { 167 throw new RuntimeException(e); 168 } 169 } 170 171 @Override 172 public void fromUSMF(USMFStatus status) { 173 prepareModel(); 174 // m.add( 175 // ResourceFactory.createResource("dc:wangSub"), 176 // ResourceFactory.createProperty("dc:wangPre"), 177 // "wangObj" 178 // ); 179 ParameterizedSparqlString pss = PQUtils.constructPQ(queryCache(INSERT_ITEM_QUERY_FILE), m); 180 this.eventIRI = m.createResource(generateSocialEventIRI(status)); 181 PQUtils.setPSSResource(pss, Variables.SOCIAL_EVENT.name, eventIRI); 182 PQUtils.setPSSLiteral(pss, Variables.SERVICE.name, status.service); 183 addUserParameters(pss, status.user, status); 184 PQUtils.setPSSLiteral(pss, Variables.SOURCE_URL.name, status.source); 185 PQUtils.setPSSLiteral(pss, Variables.TEXT.name, status.text); 186 PQUtils.setPSSLiteral(pss, Variables.DESC.name, status.description); 187 PQUtils.setPSSLiteral(pss, Variables.CAT.name, status.category); 188 PQUtils.setPSSLiteral(pss, Variables.FAV.name, status.favorites); 189 UpdateAction.execute(pss.asUpdate(), m); 190 pss = PQUtils.constructPQ(readQuery(TOUSERS_INSERT_QUERY_FILE), m); 191 // the inreply user 192 193 // the mentioned users 194 for (final User key : status.to_users) { 195 PQUtils.setPSSResource(pss, Variables.SOCIAL_EVENT.name, eventIRI); 196 addUserParameters(pss, key, status); 197 UpdateAction.execute(pss.asUpdate(), m); 198 pss.clearParams(); 199 } 200 pss = PQUtils.constructPQ(readQuery(LINK_INSERT_QUERY_FILE), m); 201 PQUtils.setPSSResource(pss, Variables.SOCIAL_EVENT.name, eventIRI); 202 for (final Link link : status.links) { 203 PQUtils.setPSSLiteral(pss, Variables.LINK.name, link.href); 204 UpdateAction.execute(pss.asUpdate(), m); 205 } 206 pss = PQUtils.constructPQ(readQuery(KEYWORDS_INSERT_QUERY_FILE), m); 207 PQUtils.setPSSResource(pss, Variables.SOCIAL_EVENT.name, eventIRI); 208 for (final String key : status.keywords) { 209 PQUtils.setPSSLiteral(pss, Variables.KEYWORD.name, key); 210 UpdateAction.execute(pss.asUpdate(), m); 211 } 212 213 cleanupModel(); 214 status.fillAnalysis(this); 215 } 216 217 private void cleanupModel() { 218 final UpdateRequest del = PQUtils.constructPQ(readQuery(DELETE_TM_NULL), m).asUpdate(); 219 UpdateAction.execute(del, m); 220 } 221 222 private void addUserParameters(ParameterizedSparqlString pss, User user, USMFStatus status) { 223 PQUtils.setPSSIri(pss, Variables.USER.name, createUserIRI(status, user)); 224 PQUtils.setPSSIri(pss, Variables.PERSON.name, createPersonIRI(status, user)); 225 PQUtils.setPSSLiteral(pss, Variables.PERSON_NAME.name, user.real_name); 226 PQUtils.setPSSLiteral(pss, Variables.PERSON_LOC.name, user.location); 227 PQUtils.setPSSLiteral(pss, new String[] { Variables.PERSON_LAT.name, Variables.PERSON_LONG.name }, user.geo); 228 PQUtils.setPSSLiteral(pss, Variables.USER_NAME.name, user.name); 229 PQUtils.setPSSLiteral(pss, Variables.USER_ID.name, user.id); 230 PQUtils.setPSSLiteral(pss, Variables.USER_LANG.name, user.language); 231 PQUtils.setPSSLiteral(pss, Variables.PERSON_LANG.name, user.language); 232 PQUtils.setPSSLiteral(pss, Variables.USER_DESC.name, user.description); 233 PQUtils.setPSSLiteral(pss, Variables.USER_AVATAR.name, user.avatar); 234 PQUtils.setPSSLiteral(pss, Variables.USER_SITE.name, user.website); 235 PQUtils.setPSSLiteral(pss, Variables.USER_PROF.name, user.profile); 236 PQUtils.setPSSLiteral(pss, Variables.USER_FOLLOWERS.name, user.subscribers); 237 PQUtils.setPSSLiteral(pss, Variables.USER_FOLLOWING.name, user.subscriptions); 238 PQUtils.setPSSLiteral(pss, Variables.USER_POSTS.name, user.postings); 239 } 240 241 @Override 242 public void 243 writeASCIIAnalysis(PrintWriter outputWriter, List<String> selectiveAnalysis, List<String> selectiveStatus) 244 { 245 if (selectiveAnalysis == null) { 246 selectiveAnalysis = new ArrayList<String>(); 247 selectiveAnalysis.addAll(this.analysis.keySet()); 248 } 249 for (final String ana : selectiveAnalysis) { 250 final RDFAnalysisProvider prov = providers.get(ana); 251 if (prov == null) 252 continue; 253 prov.addAnalysis(m, eventIRI, this); 254 } 255 256 // m.write(System.out, "N-TRIPLES"); 257 m.write(outputWriter, "N-TRIPLES"); 258 } 259 260 private String createUserIRI(USMFStatus status, User user) { 261 return String.format("%s%s/user/%s", m.getNsPrefixURI("tm"), status.service, (long) user.id); 262 } 263 264 private String createPersonIRI(USMFStatus status, User user) { 265 return String.format("%s%s/person/%s", m.getNsPrefixURI("tm"), status.service, (long) user.id); 266 } 267 268 private String generateSocialEventIRI(USMFStatus status) { 269 270 return String.format("%s%s/%s", m.getNsPrefixURI("tm"), status.service, status.id); 271 } 272 273 private synchronized void prepareModel() { 274 m = ModelFactory.createDefaultModel(); 275 m.read(new StringReader(baseModelString), ""); 276 // m.read(GeneralJSONRDF.class.getResourceAsStream("rdf/base_usmf.rdf"), 277 // ""); 278 } 279 280 @Override 281 public GeneralJSON instanceFromString(String line) { 282 GeneralJSONRDF jsonInstance = null; 283 try { 284 jsonInstance = new GeneralJSONRDF(); 285 jsonInstance.m.read(new StringReader(line), ""); 286 } catch (final Throwable e) { 287 throw new RuntimeException(e); 288 } 289 return jsonInstance; 290 } 291}