package org.basex.query.util.pkg; import static org.basex.query.util.pkg.PkgText.*; import static org.basex.util.Token.*; import org.basex.core.MainProp; import org.basex.core.Context; import org.basex.io.IOFile; import org.basex.query.QueryException; import org.basex.query.util.pkg.Package.Component; import org.basex.util.Util; import org.basex.util.hash.TokenMap; import org.basex.util.hash.TokenObjMap; import org.basex.util.hash.TokenSet; /** * Repository manager. * @author BaseX Team 2005-12, BSD License * @author Rositsa Shadura */ public final class Repo { /** Context. */ public final Context context; /** * Namespace-dictionary with all namespaces (unique names) available * in the repository, and the packages in which they are found. */ private final TokenObjMap<TokenSet> nsDict = new TokenObjMap<TokenSet>(); /** Package dictionary with installed packages and their directories. */ private final TokenMap pkgDict = new TokenMap(); /** Initialization flag (the repository can only be initialized once). */ private boolean init; /** Repository path. */ private IOFile path; /** * Constructor. * @param ctx database context */ public Repo(final Context ctx) { context = ctx; path = new IOFile(ctx.mprop.get(MainProp.REPOPATH)); } /** * Returns the namespace dictionary. Initializes the repository if not done * yet. * @return dictionary */ public TokenObjMap<TokenSet> nsDict() { init(null); return nsDict; } /** * Returns the package dictionary. Initializes the repository if not done yet. * @return dictionary */ public TokenMap pkgDict() { init(null); return pkgDict; } /** * Initializes the package repository. * @param repo repository. The default path is used if set to {@code null} */ public void init(final String repo) { if(init) return; init = true; if(repo != null) { context.mprop.set(MainProp.REPOPATH, repo); path = new IOFile(repo); } for(final IOFile dir : path.children()) { if(dir.isDir()) readPkg(dir); } } /** * Returns the path to the specified repository package. * @param pkg package * @return file reference */ public IOFile path(final String pkg) { return new IOFile(path, pkg); } /** * Removes a package from the namespace and package dictionaries when it is * deleted. * @param pkg deleted package */ public synchronized void remove(final Package pkg) { final byte[] name = pkg.uniqueName(); // delete package from namespace dictionary for(final Component comp : pkg.comps) { final byte[] uri = comp.uri; final TokenSet pkgs = nsDict.get(uri); if(pkgs.size() > 1) { pkgs.delete(name); } else { nsDict.delete(uri); } } // delete package from package dictionary pkgDict.delete(name); } /** * Adds a newly installed package to the namespace and package dictionaries. * @param pkg new package * @param dir new package directory */ public synchronized void add(final Package pkg, final String dir) { final byte[] name = pkg.uniqueName(); // update namespace dictionary for(final Component comp : pkg.comps) { if(nsDict.id(comp.uri) == 0) { nsDict.add(comp.uri, new TokenSet(name)); } else { nsDict.get(comp.uri).add(name); } } // update package dictionary pkgDict.add(name, token(dir)); } /** * Reads a package descriptor and adds components namespaces to * namespace-dictionary and packages - to package dictionary. * @param dir package directory */ private void readPkg(final IOFile dir) { final IOFile desc = new IOFile(dir, DESCRIPTOR); if(desc.exists()) { try { final Package pkg = new PkgParser(context.repo, null).parse(desc); final byte[] name = pkg.uniqueName(); // read package components for(final Component comp : pkg.comps) { // add component's namespace to namespace dictionary if(comp.uri != null) { final TokenSet ts = nsDict.get(comp.uri); if(ts != null) { ts.add(name); } else { nsDict.add(comp.uri, new TokenSet(name)); } } } // add package to package dictionary pkgDict.add(name, token(dir.name())); } catch(final QueryException ex) { Util.errln(ex.getMessage()); } } else { Util.errln(MISSDESC, dir); } } }