[9874] | 1 | package org.greenstone.gsdl3.util;
|
---|
| 2 |
|
---|
| 3 | import au.com.pharos.gdbm.GdbmFile;
|
---|
| 4 | import au.com.pharos.packing.*;
|
---|
| 5 | import au.com.pharos.gdbm.GdbmException;
|
---|
| 6 |
|
---|
[13124] | 7 | import org.apache.log4j.*;
|
---|
| 8 |
|
---|
[9874] | 9 | /** java wrapper class for gdbm - uses Java-GDBM written by Martin Pool
|
---|
| 10 | * replaces gdbmclass in the old version
|
---|
| 11 | */
|
---|
| 12 |
|
---|
| 13 | public class GDBMWrapper {
|
---|
| 14 |
|
---|
[13270] | 15 | static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GDBMWrapper.class.getName());
|
---|
[13124] | 16 |
|
---|
| 17 |
|
---|
[9874] | 18 | // Values must match those from gdbm.h - uses the definitions from GdbmFile !
|
---|
| 19 | /** Indicates that the caller will just read the database. Many
|
---|
| 20 | * readers may share a database. */
|
---|
| 21 | public final static int READER = GdbmFile.READER;
|
---|
| 22 |
|
---|
| 23 | /** The caller wants read/write access to an existing database and
|
---|
| 24 | * requires exclusive access. */
|
---|
| 25 | public final static int WRITER = GdbmFile.WRITER;
|
---|
| 26 |
|
---|
| 27 | /** The caller wants exclusive read/write access, and the database
|
---|
| 28 | * should be created if it does not already exist. */
|
---|
| 29 | public final static int WRCREAT = GdbmFile.WRCREAT;
|
---|
| 30 |
|
---|
| 31 | /** The caller wants exclusive read/write access, and the database
|
---|
| 32 | * should be replaced if it already exists. */
|
---|
| 33 | public final static int NEWDB = GdbmFile.NEWDB;
|
---|
| 34 |
|
---|
| 35 | protected GdbmFile db_=null;
|
---|
| 36 |
|
---|
| 37 | /** open the database filename, with mode mode - uses the constants
|
---|
| 38 | above, eg GdbmFile.WRITER */
|
---|
| 39 | public boolean openDatabase(String filename, int mode){
|
---|
| 40 | try {
|
---|
| 41 | if (db_!=null) {
|
---|
| 42 | db_.close();
|
---|
| 43 | }
|
---|
| 44 | db_ = new GdbmFile(filename, mode);
|
---|
| 45 | } catch ( GdbmException e) { // the database wasn't opened or created
|
---|
[13124] | 46 | logger.error("couldn't open database "+filename);
|
---|
[9874] | 47 | return false;
|
---|
| 48 | }
|
---|
| 49 | db_.setKeyPacking(new StringPacking());
|
---|
| 50 | db_.setValuePacking(new StringPacking());
|
---|
| 51 | return true;
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | /** cloase the database associated with this wrapper */
|
---|
| 55 | public void closeDatabase() {
|
---|
| 56 | try {
|
---|
| 57 | if (db_ != null) {
|
---|
| 58 | db_.close();
|
---|
| 59 | db_ = null;
|
---|
| 60 | }
|
---|
| 61 | } catch (GdbmException e) {
|
---|
| 62 | // should never get here - close never actually throws an exception
|
---|
[13124] | 63 | logger.error("error on close()");
|
---|
[9874] | 64 | }
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | /** returns a DBInfo object containing all the name-value pairs for
|
---|
| 68 | * main_key
|
---|
| 69 | * @see DBInfo
|
---|
| 70 | */
|
---|
| 71 | public DBInfo getInfo(String main_key) {
|
---|
| 72 | if (db_==null) {
|
---|
| 73 | return null;
|
---|
| 74 | }
|
---|
| 75 | String s_info;
|
---|
| 76 | try {
|
---|
| 77 | s_info = (String)db_.fetch(main_key);
|
---|
| 78 | } catch (GdbmException e) {
|
---|
[13124] | 79 | logger.error("couldn't get record");
|
---|
[9874] | 80 | return null;
|
---|
| 81 | }
|
---|
| 82 | if (s_info==null) {
|
---|
| 83 | // record not present
|
---|
[13124] | 84 | logger.error("key "+main_key+" not present in db");
|
---|
[9874] | 85 | return null;
|
---|
| 86 | }
|
---|
| 87 | DBInfo info = new DBInfo();
|
---|
| 88 |
|
---|
| 89 | String [] lines = s_info.split("\n");
|
---|
| 90 | String key;
|
---|
| 91 | String value;
|
---|
| 92 | for (int i=0; i<lines.length; i++) {
|
---|
[13124] | 93 | logger.debug("line:"+lines[i]);
|
---|
[9874] | 94 | int a = lines[i].indexOf('<');
|
---|
| 95 | int b= lines[i].indexOf('>');
|
---|
| 96 | if (a==-1 || b==-1) {
|
---|
[13124] | 97 | logger.error("bad format in db");
|
---|
[9874] | 98 | }
|
---|
| 99 | else {
|
---|
| 100 | key=lines[i].substring(a+1, b);
|
---|
| 101 | value=lines[i].substring(b+1);
|
---|
[13124] | 102 | logger.debug("key="+key+", val="+value);
|
---|
[9874] | 103 | info.addInfo(key, value);
|
---|
| 104 |
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 | return info;
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | /** sets all the name-value pairs in info as the content for key key
|
---|
| 111 | * TODO - not implemented yet */
|
---|
| 112 | public boolean setInfo(String key, DBInfo info) {
|
---|
| 113 | if (db_==null) {
|
---|
| 114 | return false;
|
---|
| 115 | }
|
---|
| 116 | return true;
|
---|
| 117 | }
|
---|
| 118 | /** sets the key value as info
|
---|
| 119 | * TODO - not implemented yet */
|
---|
| 120 | public boolean setInfo (String key, String info) {
|
---|
| 121 | if (db_==null) {
|
---|
| 122 | return false;
|
---|
| 123 | }
|
---|
| 124 | return true;
|
---|
| 125 | }
|
---|
| 126 | /** deletes the entry for key
|
---|
| 127 | * TODO - not implemented yet */
|
---|
| 128 | public boolean deleteKey(String key) {
|
---|
| 129 | if (db_==null) {
|
---|
| 130 | return false;
|
---|
| 131 | }
|
---|
| 132 | return true;
|
---|
| 133 | }
|
---|
| 134 |
|
---|
| 135 | // greenstone convenience methods - should these go into a separate class?
|
---|
| 136 | // yes I think so.
|
---|
| 137 | /** converts a greenstone OID to internal docnum */
|
---|
| 138 | public long OID2Docnum(String OID) {
|
---|
| 139 | DBInfo info = getInfo(OID);
|
---|
| 140 | if (info != null) {
|
---|
| 141 | long real_num = Long.parseLong(info.getInfo("docnum"));
|
---|
| 142 | return real_num;
|
---|
| 143 | }
|
---|
| 144 | return -1;
|
---|
| 145 | }
|
---|
| 146 | /** converts a docnum to greenstone OID */
|
---|
| 147 | public String docnum2OID(long docnum) {
|
---|
[13239] | 148 | return docnum2OID(Long.toString(docnum));
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | /** converts a docnum to greenstone OID */
|
---|
| 152 | public String docnum2OID(String docnum) {
|
---|
| 153 | DBInfo info = getInfo(docnum);
|
---|
[14531] | 154 | if (info!=null){
|
---|
| 155 | String oid = info.getInfo("section");
|
---|
| 156 | return oid;
|
---|
| 157 | }else{
|
---|
| 158 | return null;
|
---|
| 159 | }
|
---|
[9874] | 160 | }
|
---|
| 161 |
|
---|
| 162 | /** converts an external id to greenstone OID */
|
---|
| 163 | public String externalId2OID(String extid) {
|
---|
| 164 | DBInfo info = getInfo(extid);
|
---|
| 165 | if (info != null) {
|
---|
| 166 | String oid = info.getInfo("section");
|
---|
| 167 | return oid;
|
---|
| 168 | }
|
---|
| 169 | return null;
|
---|
| 170 | }
|
---|
| 171 | /** translates relative oids into proper oids:
|
---|
| 172 | * .pr (parent), .rt (root) .fc (first child), .lc (last child),
|
---|
| 173 | * .ns (next sibling), .ps (previous sibling)
|
---|
[11278] | 174 | * .np (next page), .pp (previous page) : links sections in the order that you'd read the document
|
---|
[9874] | 175 | * a suffix is expected to be present so test before using
|
---|
[11278] | 176 | */
|
---|
[9874] | 177 | public String translateOID(String oid) {
|
---|
| 178 |
|
---|
| 179 | int p = oid.lastIndexOf('.');
|
---|
| 180 | if (p != oid.length()-3) {
|
---|
[13124] | 181 | logger.info("translateoid error: '.' is not the third to last char!!");
|
---|
[9874] | 182 | return oid;
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | String top = oid.substring(0, p);
|
---|
| 186 | String suff = oid.substring(p+1);
|
---|
[11278] | 187 | // just in case we have multiple extensions, we must translate
|
---|
| 188 | // we process inner ones first
|
---|
| 189 | if (OID.needsTranslating(top)) {
|
---|
| 190 | top = translateOID(top);
|
---|
| 191 | }
|
---|
[9874] | 192 | if (suff.equals("pr")) {
|
---|
| 193 | return OID.getParent(top);
|
---|
[11278] | 194 | }
|
---|
| 195 | if (suff.equals("rt")) {
|
---|
[9874] | 196 | return OID.getTop(top);
|
---|
[11278] | 197 | }
|
---|
| 198 | if (suff.equals("np")) {
|
---|
| 199 | // try first child
|
---|
| 200 | String node_id = translateOID(top+".fc");
|
---|
| 201 | if (!node_id.equals(top)) {
|
---|
| 202 | return node_id;
|
---|
[9874] | 203 | }
|
---|
[11278] | 204 | // try next sibling
|
---|
| 205 | node_id = translateOID(top+".ns");
|
---|
| 206 | if (!node_id.equals(top)) {
|
---|
| 207 | return node_id;
|
---|
[9874] | 208 | }
|
---|
[11278] | 209 | // otherwise we keep trying parents sibling
|
---|
| 210 | String child_id = top;
|
---|
| 211 | String parent_id = OID.getParent(child_id);
|
---|
| 212 | while(!parent_id.equals(child_id)) {
|
---|
| 213 | node_id = translateOID(parent_id+".ns");
|
---|
| 214 | if (!node_id.equals(parent_id)) {
|
---|
| 215 | return node_id;
|
---|
| 216 | }
|
---|
| 217 | child_id = parent_id;
|
---|
| 218 | parent_id = OID.getParent(child_id);
|
---|
[9874] | 219 | }
|
---|
[11278] | 220 | return top; // we couldn't get a next page, so just return the original
|
---|
| 221 | }
|
---|
| 222 | if (suff.equals("pp")) {
|
---|
| 223 | String prev_sib = translateOID(top+".ps");
|
---|
| 224 | if (prev_sib.equals(top)) {
|
---|
| 225 | // no previous sibling, so return the parent
|
---|
| 226 | return OID.getParent(top);
|
---|
| 227 | }
|
---|
| 228 | // there is a previous sibling, so its either this section, or the last child of the last child..
|
---|
| 229 | String last_child = translateOID(prev_sib+".lc");
|
---|
| 230 | while (!last_child.equals(prev_sib)) {
|
---|
| 231 | prev_sib = last_child;
|
---|
| 232 | last_child = translateOID(prev_sib+".lc");
|
---|
| 233 | }
|
---|
| 234 | return last_child;
|
---|
| 235 | }
|
---|
| 236 |
|
---|
| 237 | int sibling_num = 0;
|
---|
| 238 | if (suff.equals("ss")) {
|
---|
| 239 | // we have to remove the sib num before we get top
|
---|
| 240 | p = top.lastIndexOf('.');
|
---|
| 241 | sibling_num = Integer.parseInt(top.substring(p+1));
|
---|
| 242 | top = top.substring(0, p);
|
---|
| 243 | }
|
---|
| 244 |
|
---|
| 245 | // need to get info out of gdbm db -
|
---|
| 246 | String doc_id = top;
|
---|
| 247 | if (suff.endsWith("s")) {
|
---|
| 248 | doc_id = OID.getParent(top);
|
---|
| 249 | if (doc_id.equals(top)) {
|
---|
| 250 | // i.e. we are already at the top
|
---|
[9874] | 251 | return top;
|
---|
| 252 | }
|
---|
[11278] | 253 | }
|
---|
| 254 | DBInfo info = getInfo(doc_id);
|
---|
| 255 | if (info==null) {
|
---|
[13124] | 256 | logger.info("info is null!!");
|
---|
[11278] | 257 | return top;
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | String contains = info.getInfo("contains");
|
---|
| 261 | if (contains.equals("")) {
|
---|
| 262 | // something is wrong
|
---|
| 263 | return top;
|
---|
| 264 | }
|
---|
| 265 | contains = contains.replaceAll("\"", doc_id);
|
---|
| 266 | String [] children = contains.split(";");
|
---|
| 267 | if (suff.equals("fc")) {
|
---|
| 268 | return children[0];
|
---|
| 269 | } else if (suff.equals("lc")) {
|
---|
| 270 | return children[children.length-1];
|
---|
| 271 | } else {
|
---|
| 272 | if (suff.equals("ss")) {
|
---|
| 273 | return children[sibling_num-1];
|
---|
| 274 | }
|
---|
| 275 | // find the position that we are at.
|
---|
| 276 | int i=0;
|
---|
| 277 | while (i<children.length) {
|
---|
| 278 | if (children[i].equals(top)) {
|
---|
| 279 | break;
|
---|
[9874] | 280 | }
|
---|
[11278] | 281 | i++;
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | if (suff.equals("ns")) {
|
---|
| 285 | if (i==children.length-1) {
|
---|
| 286 | return children[i];
|
---|
[9874] | 287 | }
|
---|
[11278] | 288 | return children[i+1];
|
---|
| 289 | } else if (suff.equals("ps")) {
|
---|
| 290 | if (i==0) {
|
---|
| 291 | return children[i];
|
---|
[9874] | 292 | }
|
---|
[11278] | 293 | return children[i-1];
|
---|
[9874] | 294 | }
|
---|
| 295 | }
|
---|
[11278] | 296 |
|
---|
[9874] | 297 | return top;
|
---|
| 298 | }
|
---|
| 299 | }
|
---|