001: package org.ontoware.semversion;
002:
003: import java.io.File;
004: import java.io.IOException;
005: import java.util.Iterator;
006:
007: import org.ontoware.aifbcommons.collection.ClosableIterator;
008: import org.ontoware.rdf2go.SparqlUtil;
009: import org.ontoware.rdf2go.exception.ModelException;
010: import org.ontoware.rdf2go.model.Diff;
011: import org.ontoware.rdf2go.model.Model;
012: import org.ontoware.rdf2go.model.Statement;
013: import org.ontoware.rdf2go.model.node.URI;
014: import org.ontoware.rdf2go.model.node.Variable;
015: import org.ontoware.rdf2go.model.node.impl.PlainLiteralImpl;
016: import org.ontoware.rdf2go.model.node.impl.URIImpl;
017: import org.ontoware.rdf2go.vocabulary.RDF;
018: import org.ontoware.rdfreactor.runtime.Bridge;
019: import org.ontoware.semversion.impl.SyntacticDiffEngine;
020: import org.ontoware.semversion.impl.TripleStore;
021: import org.ontoware.semversion.impl.UserImpl;
022: import org.slf4j.Logger;
023: import org.slf4j.LoggerFactory;
024:
025: /**
026: * Main class of SemVersion.
027: *
028: * @author voelkel
029: */
030: /**
031: * @author voelkel
032: *
033: */
034: public class SemVersion {
035:
036: private Logger log = LoggerFactory.getLogger(SemVersion.class);
037:
038: /**
039: * SemVersion.SEMVERSION_NS + "#hasBlankNodeID
040: */
041: public static final URI BLANK_NODE_ID = new URIImpl(
042: SemVersion.SEMVERSION_NS + "#hasBlankNodeID");
043:
044: public static final String MAIN_BRANCH = new String("main");
045:
046: public static final URI MAIN_MODEL_URI = new URIImpl(
047: SemVersion.SEMVERSION_NS + "#mainModel");
048:
049: public static final String SEMVERSION_NS = "http://purl.org/net/semversion";
050:
051: public static final URI SEMVERSIONIMPL = new URIImpl(
052: SemVersion.SEMVERSION_NS + "/property#SemVersionImpl");
053:
054: public static final URI TRIPLESTORE = new URIImpl(
055: SemVersion.SEMVERSION_NS + "/property#TripleStore");
056:
057: /**
058: * Denote the status of a Version is 'valid'
059: */
060: public static final String VALID = new String("valid");
061:
062: private org.ontoware.rdf2go.model.Model mainModel;
063:
064: private boolean startup = false;
065:
066: private TripleStore ts;
067:
068: public SemVersion() throws Exception {
069: }
070:
071: private void checkStartup() {
072: if (!startup)
073: throw new IllegalStateException(
074: "Please call startup(..) first");
075: }
076:
077: /**
078: * Delete all data. CAUTION.
079: */
080: public void clear() {
081: checkStartup();
082: this .ts.deleteStore();
083: }
084:
085: /**
086: * Admin taks: Create a new user account.
087: *
088: * @param name
089: * @param pass
090: * @return the new User.
091: */
092: public User createUser(String name, String pass) {
093: checkStartup();
094: try {
095: ClosableIterator<? extends Statement> it = mainModel
096: .findStatements(
097: Variable.ANY,
098: org.ontoware.semversion.impl.generated.User.NAME,
099: new PlainLiteralImpl(name));
100: if (it.hasNext())
101: throw new RuntimeException("User " + name
102: + " already exists");
103: return new UserImpl(mainModel, mainModel
104: .newRandomUniqueURI(), name, pass);
105: } catch (Exception e) {
106: throw new RuntimeException(e);
107: }
108: }
109:
110: /**
111: * For testing purposes only: Removes all stored statements
112: *
113: * @throws ModelException
114: */
115: public void deleteStore() throws ModelException {
116: getTripleStore().deleteStore();
117: }
118:
119: /**
120: * For debugging purposes. Dumps the whole store to System.out.
121: */
122: public void dump() {
123:
124: try {
125: getTripleStore().dump();
126: } catch (Exception e) {
127: e.printStackTrace();
128: }
129: }
130:
131: public Model getMainModel() {
132: checkStartup();
133: return this .mainModel;
134: }
135:
136: /**
137: * A semantic diff is calculated like this: <code>
138: * A' = transitive closure of (A)
139: * B' = transitive closure of (B)
140: * return diff(A',B')
141: * </code>
142: *
143: * @param model_A
144: * @param model_B
145: * @return a semantic Diff
146: */
147: public Diff getSemanticDiff_RDFS(Model model_A, Model model_B) {
148: try {
149: return SemanticDiffEngine.getSemanticDiff_RDFS(model_A,
150: model_B);
151: } catch (Exception e) {
152: throw new RuntimeException(e);
153: }
154: }
155:
156: /**
157: * @param model_A
158: * @param model_B
159: * @return a Diff between the two models. The diff will e.g. contain as
160: * added triples those present in B but not in A.
161: */
162: public Diff getSyntacticDiff(Model model_A, Model model_B) {
163: try {
164: return SyntacticDiffEngine.getSyntacticDiff(model_A,
165: model_B);
166: } catch (Exception e) {
167: throw new RuntimeException(e);
168: }
169: }
170:
171: /*
172: * (non-Javadoc)
173: *
174: * @see org.ontoware.semversion.SemVersion#getTripleStore()
175: */
176: public TripleStore getTripleStore() {
177: checkStartup();
178: return this .ts;
179: }
180:
181: public User getUser(String name, String pass) {
182: checkStartup();
183: Iterator<? extends Object> it = Bridge
184: .getSparqlSelectSingleVariable(
185: mainModel,
186: org.ontoware.semversion.impl.generated.User.class,
187: "SELECT ?x WHERE {"
188: + // .
189: "?x <"
190: + RDF.type
191: + "> <"
192: + org.ontoware.semversion.impl.generated.User.RDFS_CLASS
193: + "> ."
194: + // .
195: "?x <"
196: + org.ontoware.semversion.impl.generated.User.NAME
197: + "> "
198: + SparqlUtil.toSparqlLiteral(name)
199: + " ."
200: +
201: // .
202: "?x <"
203: + org.ontoware.semversion.impl.generated.User.PASSWORD
204: + "> "
205: + SparqlUtil.toSparqlLiteral(pass)
206: + " ." + // .
207: "}");
208:
209: if (it.hasNext()) {
210: org.ontoware.semversion.impl.generated.User user = (org.ontoware.semversion.impl.generated.User) it
211: .next();
212: assert !it.hasNext() : "there should be only one user with this name + pass";
213: return new UserImpl(user);
214: } else {
215: return null;
216: }
217: }
218:
219: public User getUser(URI uri) {
220: checkStartup();
221: return new UserImpl(
222: new org.ontoware.semversion.impl.generated.User(
223: mainModel, uri, false));
224: }
225:
226: /**
227: * Log in to SemVersion.
228: *
229: * @param username
230: * @param password
231: * @return a Session. All further access to SemVersion happens via the
232: * Session.
233: * @throws LoginException
234: */
235: public Session login(String username, String password)
236: throws LoginException {
237: User user = getUser(username, password);
238: assert user == null || user.getName().equals(username);
239: if (user == null)
240: throw new LoginException("Could not login '" + username
241: + "', check username & password");
242: return new Session(user, this );
243: }
244:
245: /**
246: * Save without shutdown.
247: *
248: * @throws IOException
249: */
250: public void save() throws IOException {
251: checkStartup();
252: log
253: .info("SemVersion now uses auto-commit. There is no need to save.");
254: }
255:
256: /**
257: * Persists changes. Changes might be persisted before already.
258: *
259: * @throws IOException
260: */
261:
262: public void shutdown() throws IOException {
263: checkStartup();
264: mainModel.close();
265: }
266:
267: /**
268: * Starts up SemVersion and reads the main model into memory. This is a
269: * small model which knows the relations between other models.
270: *
271: * @param storageDir
272: * @throws IOException
273: */
274: public void startup(File storageDir) throws IOException {
275: // look for property file
276: // File propFile =
277: // // ResourceUtils.findFileAsResource( ..., true);
278: // new File("./etc/semversion.properties");
279: // Properties props = new Properties();
280: // props.load(new FileInputStream(propFile));
281: //
282: // // use properties
283: // String storageDirName = props.getProperty("StorageDir");
284: // log.debug("storage dir = '" + storageDirName + "'");
285: // if (storageDirName == null)
286: // storageDirName = "./storage";
287: // this.storageDir = new File(storageDirName);
288: if (!storageDir.exists()) {
289: log.warn("Not found, creating " + storageDir);
290: storageDir.mkdirs();
291: }
292: assert storageDir.exists() : storageDir.getAbsoluteFile()
293: + " not found";
294:
295: // startup persistence layer
296: ts = new TripleStore(storageDir);
297:
298: // load main model from store
299: mainModel = ts.getPersistentModel(MAIN_MODEL_URI);
300: // configure main model
301: mainModel.setProperty(SEMVERSIONIMPL, this );
302: mainModel.setProperty(TRIPLESTORE, ts);
303: startup = true;
304: }
305:
306: /**
307: * @return a session with the user "anonymous" logged in. This user is
308: * created if necessary.
309: */
310: public Session createAnonymousSession() {
311: if (getUser("anonymous", "") == null)
312: createUser("anonymous", "");
313: try {
314: return login("anonymous", "");
315: } catch (LoginException e) {
316: throw new AssertionError(
317: "This cannot happen as we create the user before logging in");
318: }
319: }
320:
321: }
|