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