1 36 37 package com.caucho.doc.javadoc; 38 39 import com.caucho.config.ConfigException; 40 import com.caucho.config.types.Period; 41 import com.caucho.loader.Environment; 42 import com.caucho.log.Log; 43 import com.caucho.server.webapp.Application; 44 import com.caucho.server.webapp.PathMapping; 45 import com.caucho.util.CharBuffer; 46 import com.caucho.util.Crc64; 47 import com.caucho.util.L10N; 48 import com.caucho.vfs.Path; 49 import com.caucho.vfs.ReadStream; 50 import com.caucho.vfs.Vfs; 51 import com.caucho.vfs.WriteStream; 52 53 import java.io.IOException ; 54 55 import java.sql.Connection ; 56 import java.sql.ResultSet ; 57 import java.sql.SQLException ; 58 import java.sql.Statement ; 59 60 import java.util.Collection ; 61 import java.util.Iterator ; 62 import java.util.LinkedHashMap ; 63 import java.util.LinkedList ; 64 import java.util.logging.Level ; 65 import java.util.logging.Logger ; 66 67 import javax.naming.Context ; 68 import javax.naming.InitialContext ; 69 import javax.naming.NamingException ; 70 71 import javax.sql.DataSource ; 72 73 76 public class Store { 77 static protected final Logger log = Log.open(Store.class); 78 static final L10N L = new L10N(Store.class); 79 80 private final static String STORE_JNDINAME = "resin-javadoc/store"; 81 82 private String _dataSource; 83 private LinkedHashMap <String ,Api> _api = new LinkedHashMap <String ,Api>(); 84 85 private Path _timestampFile; 86 private String _tableNameFile = "javadoc_file"; 87 private String _tableNameItem = "javadoc_item"; 88 private long _httpCachePeriod; 89 90 private String _startPage = "overview.jsp"; 91 private boolean _showAddHelp; 92 93 private long _crc64 = 0; 94 private DataSource _pool; 95 96 private Exception _initError; 97 98 101 static public Store getInstance() 102 throws NamingException  103 { 104 Context env = (Context ) new InitialContext ().lookup("java:comp/env"); 105 106 Store store = (Store) env.lookup(STORE_JNDINAME); 107 108 if (store == null) 109 throw new NamingException (L.l("`{0}' is an unknown Store",STORE_JNDINAME)); 110 return store; 111 } 112 113 116 public void setDataSource(String dataSource) 117 { 118 _dataSource = dataSource; 119 } 120 121 125 public void setTimestampFile(Path timestampFile) 126 { 127 _timestampFile = timestampFile; 128 } 129 130 133 public void addApi(Api api) 134 throws ConfigException 135 { 136 if (_api.get(api.getId()) != null) 137 throw new ConfigException(L.l("id `{0}' already used, id must be unique",api.getId())); 138 _api.put(api.getId(),api); 139 } 140 141 144 public Api getApi(String id) 145 { 146 return _api.get(id); 147 } 148 149 152 public Collection <Api> getAllApi() 153 { 154 return _api.values(); 155 } 156 157 161 public void setTableNameItem(String tableNameItem) 162 { 163 _tableNameItem = tableNameItem; 164 } 165 166 169 public String getTableNameItem() 170 { 171 return _tableNameItem; 172 } 173 174 178 public void setTableNameFile(String tableNameFile) 179 { 180 _tableNameFile = tableNameFile; 181 } 182 183 186 public String getTableNameFile() 187 { 188 return _tableNameFile; 189 } 190 191 202 public void setHttpCachePeriod(Period httpCachePeriod) 203 { 204 _httpCachePeriod = httpCachePeriod.getPeriod(); 205 } 206 207 210 public long getHttpCachePeriod() 211 { 212 return _httpCachePeriod; 213 } 214 215 219 public void setStartPage(String startPage) 220 { 221 _startPage = startPage; 222 } 223 224 227 public String getStartPage() 228 { 229 return _startPage; 230 } 231 232 235 public void setShowAddHelp(boolean showAddHelp) 236 { 237 _showAddHelp = showAddHelp; 238 } 239 240 243 public boolean getShowAddHelp() 244 { 245 return _showAddHelp; 246 } 247 248 public void init() 249 { 250 try { 251 if (_timestampFile == null) 252 _timestampFile = Vfs.lookup("WEB-INF/timestamp"); 253 254 try { 255 Context env = (Context ) new InitialContext ().lookup("java:comp/env"); 256 257 _pool = (DataSource ) env.lookup(_dataSource); 258 259 if (_pool == null) 260 throw new ConfigException(L.l("`{0}' is an unknown DataSource, database has not been configured or is not configured properly.",_dataSource)); 261 } catch (NamingException e) { 262 throw new ConfigException(e); 263 } 264 265 267 for (Iterator <Api> i = _api.values().iterator(); i.hasNext(); ) { 268 Api api = i.next(); 269 _crc64 = api.generateCrc64(_crc64); 270 } 271 _crc64 = Crc64.generate(_crc64,_dataSource); 272 _crc64 = Crc64.generate(_crc64,_timestampFile.toString()); 273 _crc64 = Crc64.generate(_crc64,_tableNameFile); 274 _crc64 = Crc64.generate(_crc64,_tableNameItem); 275 276 try { 277 if (isNeedUpdate()) 278 createFromIndex(); 279 } catch (Exception ex) { 280 throw new ConfigException(ex); 281 } 282 283 285 Application app = Application.getLocal(); 286 287 CharBuffer cb = CharBuffer.allocate(); 288 289 for (Iterator <Api> i = _api.values().iterator(); i.hasNext(); ) { 290 Api api = i.next(); 291 292 if (api.isLocalAbsolute()) { 293 cb.clear(); 294 cb.append("/"); 295 cb.append(api.getId()); 296 cb.append("/*"); 297 String urlPattern = cb.toString(); 298 299 PathMapping pm = new PathMapping(); 300 pm.setUrlPattern(urlPattern); 301 pm.setRealPath(api.getLocation()); 302 try { 303 app.addPathMapping(pm); 304 } catch (Exception ex) { 305 throw new ConfigException(ex); 306 } 307 } 308 } 309 310 cb.free(); 311 312 313 316 for (Iterator <Api> i = _api.values().iterator(); i.hasNext(); ) { 317 Api api = i.next(); 318 if (api.isLocal()) { 319 Path index = api.getLocationPath().lookup("index.html"); 320 Environment.addDependency(index); 321 } 322 } 323 } catch (Exception ex) { 324 log.log(Level.FINE,"resin-javadoc init error",ex); 325 _initError = ex; 326 } 327 } 328 329 public Exception getInitError() 330 { 331 return _initError; 332 } 333 334 338 public boolean isNeedUpdate() 339 { 340 try { 341 ReadStream rs = _timestampFile.openRead(); 342 String lms = rs.readLine(); 343 long crc = Long.parseLong(lms); 344 lms = rs.readLine(); 345 long tsfiles = Long.parseLong(lms); 346 rs.close(); 347 348 if (crc != _crc64) { 349 log.info(L.l("javadoc index needs update - config has changed")); 350 if (log.isLoggable(Level.FINE)) 351 log.finer(L.l("timestamp file {0} lastmodified {1}",_timestampFile,new Long (crc))); 352 } 353 else if (tsfiles != getTimestampForLocalFiles()) { 354 log.info(L.l("javadoc index needs update - a local api has changed")); 355 } 356 else { 357 return false; 358 } 359 } catch (Exception ex) { 360 log.info(L.l("javadoc index needs update - timestamp file could not be read")); 361 if (log.isLoggable(Level.FINE)) 362 log.finer(L.l("timestamp file {0} {1}",_timestampFile,ex)); 363 } 364 365 return true; 366 } 367 368 372 public void createFromIndex() 373 throws SQLException , IOException  374 { 375 long st = System.currentTimeMillis(); 376 int cnt = 0; 377 378 log.info(L.l("creating javadoc index db entries")); 379 Connection conn = null; 380 try { 381 conn = _pool.getConnection(); 382 383 StoreWriter sw = new StoreWriter(this); 384 sw.clear(conn); 385 for (Iterator <Api> i = _api.values().iterator(); i.hasNext(); ) { 386 Api api = i.next(); 387 cnt += sw.add(conn,api); 388 } 389 } finally { 390 try { 391 if (conn != null) 392 conn.close(); 393 } catch (SQLException e) { 394 log.warning(L.l("conn.close() error",e)); 395 } 396 } 397 398 updateTimestampFile(); 399 400 long tm = System.currentTimeMillis() - st; 401 log.info(L.l("created {0} javadoc index entries in {1}sec", new Integer (cnt), new Double ( (double) tm / 1000.0))); 402 } 403 404 private long getTimestampForLocalFiles() 405 { 406 long ts = 0L; 407 for (Iterator <Api> i = _api.values().iterator(); i.hasNext(); ) { 408 Api api = i.next(); 409 if (api.isLocal()) { 410 ts += api.getLocationPath().lookup("index.html").getLastModified(); 411 } 412 } 413 414 return ts; 415 } 416 417 private void updateTimestampFile() 418 throws IOException  419 { 420 _timestampFile.getParent().mkdirs(); 421 WriteStream ws = _timestampFile.openWrite(); 422 ws.println(_crc64); 423 ws.println(getTimestampForLocalFiles()); 424 ws.close(); 425 } 426 427 436 public LinkedList <JavadocItem> query(String query, int offset, int limit) 437 throws SQLException 438 { 439 LinkedList <JavadocItem> results = new LinkedList <JavadocItem>(); 440 441 try { 442 int type = -1; 443 444 int i = query.indexOf(' '); 445 if (i > -1) { 446 String t = query.substring(0,i); 447 if (t.equals("package")) 448 type = JavadocItem.PACKAGE; 449 else if (t.equals("class")) 450 type = JavadocItem.CLASS; 451 else if (t.equals("method")) 452 type = JavadocItem.METHOD; 453 else if (t.equals("var")) 454 type = JavadocItem.VARIABLE; 455 else if (t.equals("any")) 456 type = JavadocItem.ANY; 457 458 if (type > -1) { 459 while (i < query.length() && Character.isWhitespace(query.charAt(i))) 460 i++; 461 if (i >= query.length()) 462 return results; 463 else 464 query = query.substring(i); 465 } 466 } 467 468 469 if (query.length() > 0 && Character.isUpperCase(query.charAt(0))) { 471 int di = query.indexOf('.'); 472 if (di > -1 ) { 473 CharBuffer cb = CharBuffer.allocate(); 474 cb.append('*'); 475 cb.append(query); 476 cb.append('*'); 477 query = cb.close(); 478 } 479 } 480 481 if (type < 0) 482 type = JavadocItem.ANY; 483 484 Connection conn = null; 485 try { 486 conn = _pool.getConnection(); 487 488 Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY); 489 boolean like = query.indexOf("*") > -1 ? true : false; 491 String nameToUse = (query.indexOf(".") > -1) ? "item.fullname" : "item.name"; 492 String safequery = escapeSQL(query); 493 494 CharBuffer cb = CharBuffer.allocate(); 495 cb.append("SELECT item.name,item.fullname,item.typ,item.anchor,item.description,file.api,file.path FROM "); 496 cb.append(getTableNameItem()); 497 cb.append(" AS item, "); 498 cb.append(getTableNameFile()); 499 cb.append(" AS file WHERE file.id = item.file_id"); 500 501 if (type != JavadocItem.ANY) { 502 cb.append(" AND item.typ = "); 503 cb.append(type); 504 } 505 String q_select = cb.close(); 506 507 if (like) { 508 cb = CharBuffer.allocate(); 509 cb.append(q_select); 510 cb.append(" AND "); 511 cb.append(nameToUse); 512 cb.append(" LIKE '"); 513 cb.append(safequery); 514 cb.append("'"); 515 516 results = doQuery(safequery,stmt,cb,offset,limit,results); 517 } 518 else { 519 cb = CharBuffer.allocate(); 520 cb.append(q_select); 521 cb.append(" AND "); 522 cb.append(nameToUse); 523 cb.append(" LIKE '"); 524 cb.append(safequery); 525 cb.append("%'"); 526 results = doQuery(safequery,stmt,cb,offset,limit,results); 527 } 528 529 if (results.size() > 0) { 531 JavadocItem item = results.getFirst(); 532 if (item.getName().equals(query) || item.getFullName().equals(query)) { 533 item.setExact(true); 534 } 535 } 536 stmt.close(); 537 } finally { 538 if (conn != null) 539 conn.close(); 540 } 541 } 542 catch (SQLException ex) { 543 if (log.isLoggable(Level.CONFIG)) 544 log.log(Level.CONFIG,L.l("error with query `{0}': {1}",query,ex.getMessage())); 545 throw ex; 546 } 547 548 return results; 549 } 550 551 private String escapeSQL(String q) 552 { 553 CharBuffer cb = CharBuffer.allocate(); 554 555 for (int i = 0; i < q.length(); i++) { 556 char c = q.charAt(i); 557 switch (c) { 558 case '\'': 559 cb.append("\\'"); 560 break; 561 case '\"': 562 cb.append("\\\""); 563 break; 564 case '*': 565 cb.append("%"); 566 break; 567 568 case '%': 569 cb.append('\\'); 570 default: 571 cb.append(c); 572 } 573 } 574 575 return cb.close(); 576 } 577 578 private LinkedList <JavadocItem> doQuery(String query, Statement stmt, CharBuffer cb, int offset, int limit, LinkedList <JavadocItem> results) 579 throws SQLException  580 { 581 if (limit <= 0) { 582 return results; 583 } 584 585 cb.append(" ORDER BY if(item.name = '"); 586 cb.append(query); 587 cb.append("' OR item.fullname = '"); 588 cb.append(query); 589 cb.append("',0,1) "); 590 cb.append(",item.typ"); 591 cb.append(", LENGTH(item.name)"); 592 cb.append(" LIMIT "); 593 cb.append(limit); 594 if (offset > 0) { 595 cb.append(" OFFSET "); 596 cb.append(offset); 597 } 598 599 600 String q = cb.close(); 601 log.finest(L.l("query is [{0}]",q)); 602 603 ResultSet rs = stmt.executeQuery(q); 604 try { 605 606 while (rs.next()) { 607 results.add(new JavadocItem( 608 rs.getString(1), rs.getString(2), rs.getInt(3), rs.getString(4), rs.getString(5), new JavadocFile(_api.get(rs.getString(6)), rs.getString(7)) )); 616 } 617 } finally { 618 rs.close(); 619 } 620 621 return results; 622 623 } 624 625 } 626 627 | Popular Tags |