package org.basex.core;
import static org.basex.core.Text.*;
import org.basex.data.Data;
import org.basex.data.MetaData;
import org.basex.data.Nodes;
import org.basex.index.Resources;
import org.basex.query.util.pkg.Repo;
import org.basex.server.ClientListener;
import org.basex.server.Sessions;
/**
* This class serves as a central database context.
* It references the currently opened database. Moreover, it provides
* references to the currently used, marked and copied node sets.
*
* This class should only be instantiated once in a project; otherwise,
* database updates may lead to conflicts.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class Context {
/** Client listener. Set to {@code null} in standalone/server mode. */
public final ClientListener listener;
/** Client-related properties. */
public final Prop prop = new Prop();
/** Main properties. */
public final MainProp mprop;
/** Client connections. */
public final Sessions sessions;
/** Event pool. */
public final Events events;
/** Database pool. */
public final Datas datas;
/** Users. */
public final Users users;
/** Package repository. */
public final Repo repo;
/** User reference. */
public User user;
// GUI references
/** Marked nodes. */
public Nodes marked;
/** Copied nodes. */
public Nodes copied;
/** Focused node. */
public int focused = -1;
/** Database path. */
private String path;
/** Node context. */
private Nodes current;
/** Process locking. */
private final Lock lock;
/** Data reference. */
private Data data;
/**
* Default constructor, which should only be called once in a project.
*/
public Context() {
listener = null;
mprop = new MainProp();
datas = new Datas();
events = new Events();
sessions = new Sessions();
lock = new Lock(this);
users = new Users(true);
repo = new Repo(this);
user = users.get(ADMIN);
}
/**
* Constructor, passing on the main context.
* The {@link #user} reference must be set after calling this method.
* @param ctx parent database context
* @param cl client listener
*/
public Context(final Context ctx, final ClientListener cl) {
listener = cl;
mprop = ctx.mprop;
datas = ctx.datas;
events = ctx.events;
sessions = ctx.sessions;
lock = ctx.lock;
users = ctx.users;
repo = ctx.repo;
}
/**
* Closes the database context.
*/
public synchronized void close() {
while(!sessions.isEmpty()) sessions.get(0).quit();
datas.close();
}
/**
* Returns {@code true} if the current context belongs to a client user.
* @return result of check
*/
public boolean client() {
return listener != null;
}
/**
* Returns {@code true} if the current node set contains all documents.
* @return result of check
*/
public boolean root() {
return current != null && current.root;
}
/**
* Returns the current data reference.
* @return data reference
*/
public Data data() {
return data;
}
/**
* Returns the current node context.
* @return node set
*/
public Nodes current() {
if(current == null && data != null) {
final Resources res = data.resources;
current = new Nodes(
(path == null ? res.docs() : res.docs(path)).toArray(), data);
current.root = path == null;
}
return current;
}
/**
* Sets the current node context.
* @param curr node set
*/
public void current(final Nodes curr) {
current = curr;
}
/**
* Sets the specified data instance as current database.
* @param d data reference
*/
public void openDB(final Data d) {
openDB(d, null);
}
/**
* Sets the specified data instance as current database and restricts
* the context nodes to the given path.
* @param d data reference
* @param p database path
*/
public void openDB(final Data d, final String p) {
data = d;
path = p;
copied = null;
set(null, new Nodes(d));
}
/**
* Resets the current database context.
*/
public void closeDB() {
data = null;
copied = null;
set(null, null);
}
/**
* Sets the current context and marked node set and resets the focus.
* @param curr context set
* @param mark marked nodes
*/
public void set(final Nodes curr, final Nodes mark) {
current = curr;
marked = mark;
focused = -1;
}
/**
* Invalidates the current node set.
*/
public void update() {
current = null;
}
/**
* Adds the specified data reference to the pool.
* @param d data reference
*/
public void pin(final Data d) {
datas.add(d);
}
/**
* Pins the specified database.
* @param name name of database
* @return data reference
*/
public Data pin(final String name) {
return datas.pin(name);
}
/**
* Unpins a data reference.
* @param d data reference
* @return true if reference was removed from the pool
*/
public boolean unpin(final Data d) {
return datas.unpin(d);
}
/**
* Checks if the specified database is pinned.
* @param db name of database
* @return int use-status
*/
public boolean pinned(final String db) {
return datas.pinned(db);
}
/**
* Registers a process.
* @param w writing flag
*/
public void register(final boolean w) {
lock.lock(w);
}
/**
* Unregisters a process.
* @param w writing flag
*/
public void unregister(final boolean w) {
lock.unlock(w);
}
/**
* Adds the specified client session.
* @param s session to be added
*/
public void add(final ClientListener s) {
sessions.add(s);
}
/**
* Removes the specified client session.
* @param s session to be removed
*/
public void delete(final ClientListener s) {
sessions.remove(s);
}
/**
* Checks if the current user has the specified permission.
* @param p requested permission
* @param md optional meta data reference
* @return result of check
*/
public boolean perm(final int p, final MetaData md) {
final User us = md == null || p == User.CREATE || p == User.ADMIN ? null :
md.users.get(user.name);
return (us == null ? user : us).perm(p);
}
}