001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: /*
042: * VisualSQLEditorMetaDataImpl.java
043: *
044: * Retrieves the meta data for a datasource/datasourceinfo
045: * Created on April 30, 2005, 5:36 PM
046:
047: */
048:
049: package org.netbeans.modules.visualweb.dataconnectivity.customizers;
050:
051: import org.netbeans.modules.visualweb.dataconnectivity.Log;
052: import org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfo;
053: import org.netbeans.modules.visualweb.dataconnectivity.model.DataSourceInfo.TestConnectionResults;
054: import org.netbeans.modules.visualweb.dataconnectivity.model.DatasourceConnectionListener;
055: import org.netbeans.modules.db.sql.visualeditor.api.VisualSQLEditorMetaData;
056: import org.netbeans.modules.visualweb.dataconnectivity.sql.DatabaseMetaDataHelper;
057: import java.sql.Connection;
058: import java.sql.DatabaseMetaData;
059:
060: import org.netbeans.modules.visualweb.dataconnectivity.model.DatasourceConnectionListener;
061: import java.sql.ResultSet;
062: import java.sql.SQLException;
063: import java.util.ArrayList;
064: import java.util.Arrays;
065: import java.util.Hashtable;
066: import java.util.List;
067: import org.netbeans.modules.visualweb.dataconnectivity.sql.DesignTimeDataSourceHelper;
068: import org.openide.ErrorManager;
069:
070: /**
071: * Database meta data cache for the QueryBuilder.
072: *
073: * @author jfbrown
074: */
075: public class VisualSQLEditorMetaDataImpl implements
076: VisualSQLEditorMetaData {
077:
078: private int hashSizeForTables = 30;
079:
080: private DataSourceInfo dataSourceInfo = null;
081: private DatabaseMetaData databaseMetaData = null;
082: private DatabaseMetaDataHelper dbmdh = null;
083:
084: private static Hashtable dataSourceCache = new Hashtable();
085:
086: /**
087: * Factory methods for finding a cache for a datasource.
088: */
089: public static synchronized VisualSQLEditorMetaData getDataSourceCache(
090: String dsName) throws SQLException {
091: VisualSQLEditorMetaData cache = (VisualSQLEditorMetaData) dataSourceCache
092: .get(dsName);
093: if (cache == null) {
094: logInfo("Creating cache for " + dsName);
095: cache = new VisualSQLEditorMetaDataImpl(dsName);
096: dataSourceCache.put(dsName, cache);
097: }
098: return cache;
099: }
100:
101: public static synchronized boolean hasDataSourceCache(String dsName) {
102: VisualSQLEditorMetaData cache = (VisualSQLEditorMetaData) dataSourceCache
103: .get(dsName);
104: if (cache == null) {
105: return false;
106: }
107: return true;
108: }
109:
110: public static synchronized void removeDataSourceCache(String dsName)
111: throws SQLException {
112: VisualSQLEditorMetaDataImpl cache = (VisualSQLEditorMetaDataImpl) dataSourceCache
113: .get(dsName);
114: if (cache != null) {
115: cache.refresh();
116: dataSourceCache.remove(dsName);
117: logInfo("Removed cache for " + dsName);
118: }
119: }
120:
121: /** Constructor */
122:
123: static final String contextSuffix = "java:comp/env/jdbc/"; // NOI18N
124:
125: public VisualSQLEditorMetaDataImpl(String dsName)
126: throws SQLException {
127: try {
128: if (dsName.startsWith(contextSuffix))
129: dsName = dsName.substring(contextSuffix.length());
130: dataSourceInfo = DesignTimeDataSourceHelper
131: .getDsInfo(dsName);
132:
133: // TODO: add listeners to dataSourceInfo for DatabaseMetaDataHelper changes.
134: dataSourceInfo.addConnectionListener(listener);
135:
136: initMetaData();
137: } catch (SQLException sqle) {
138: Log.log("Could not create cache for "
139: + sqle.getLocalizedMessage());
140: throw sqle;
141: }
142: }
143:
144: private DatasourceConnectionListener listener = new DatasourceConnectionListener() {
145: public void dataSourceConnectionModified() {
146: logInfo(dataSourceInfo.getName()
147: + " connectionModified event.");
148: refresh();
149: }
150: };
151:
152: public void initMetaData() throws SQLException {
153: dbmdh = dataSourceInfo.getDatabaseMetaDataHelper();
154: databaseMetaData = dbmdh.getMetaData();
155: refreshCacheTables();
156: }
157:
158: public void refresh() {
159: logInfo(dataSourceInfo.getName() + " nulling cache.");
160: dbmdh = null;
161: databaseMetaData = null;
162: refreshCacheTables();
163: }
164:
165: /**
166: * clears the cache held in this instance.
167: */
168: public void refreshCacheTables() {
169: columnNameTable.clear();
170: fkExportedTable.clear();
171: fkImportedTable.clear();
172: allTables = null;
173: allColumnsTable.clear();
174: allColumnsTableLoaded = false;
175: pkTable.clear();
176: identifierQuoteString = null;
177: }
178:
179: // public String[] getSchemas() {
180: // // logInfo( dataSourceInfo.getName() + " getting schemas." ) ;
181: // return dataSourceInfo.getDataSource().getSchemas() ;
182: // }
183:
184: /*
185: * Updated version of getSchemas -- returns List instead of Array
186: */
187: public List<String> getSchemas() {
188: List<String> schemas = Arrays.asList(dataSourceInfo
189: .getDataSource().getSchemas());
190: return schemas;
191: }
192:
193: /***
194: * this validates the connection to the database.
195: * returns true if valid connection.
196: * If not valid, throws exception.
197: * If the connection fails, we retry once.
198: *
199: * If users get an SQLException on any other method, they
200: * should call this. If this method returns true, then retry the
201: * method. If it fails again, then the
202: * method is the issue and there's probably no way for the consumer
203: * to recover. If this method throws an exception, then
204: * the database isn't available.
205: */
206: // public boolean checkDataBaseConnection() throws SQLException {
207: // boolean good = dataSourceInfo.testConnection() ;
208: // if ( ! good ) {
209: // TestConnectionResults res = dataSourceInfo.getLastTestResults() ;
210: // refresh() ;
211: // throw res.sqlExceptionRootCause ;
212: // }
213: // return good ;
214: // }
215: /**
216: * Returns the list of tables and views in the datasource's schemas.
217: */
218: private List<List<String>> allTables = null;
219:
220: public List<List<String>> getTables() throws SQLException {
221: if (dbmdh == null)
222: initMetaData();
223:
224: if (allTables != null)
225: return allTables;
226:
227: logInfo(dataSourceInfo.getName() + " loading tables");
228:
229: allTables = new ArrayList<List<String>>();
230:
231: String[] schemas = dataSourceInfo.getSchemas();
232: if (schemas != null && schemas.length > 0) {
233: for (int scnt = 0; scnt < schemas.length; scnt++) {
234: logInfo(" schema " + schemas[scnt]);
235: String tabs[] = dbmdh.getTables(schemas[scnt]);
236: for (int icnt = 0; icnt < tabs.length; icnt++) {
237: allTables.add(Arrays
238: .asList(parseTableName(tabs[icnt])));
239: }
240: String views[] = dbmdh.getViews(schemas[scnt]);
241: for (int icnt = 0; icnt < views.length; icnt++) {
242: allTables.add(Arrays
243: .asList(parseTableName(views[icnt])));
244: }
245: }
246: } else {
247: logInfo(" all schemas");
248: // get all of them.
249: String tabs[] = dbmdh.getTables();
250: for (int icnt = 0; icnt < tabs.length; icnt++) {
251: allTables
252: .add(Arrays.asList(parseTableName(tabs[icnt])));
253: }
254: String views[] = dbmdh.getViews();
255: for (int icnt = 0; icnt < views.length; icnt++) {
256: allTables.add(Arrays
257: .asList(parseTableName(views[icnt])));
258: }
259: }
260: logInfo(dataSourceInfo.getName() + " tables loaded "
261: + allTables.size());
262:
263: return allTables;
264: }
265:
266: // This will replace the original getTables() above, if we ever resolve the issue
267: // of schemas in DataSources/DatabaseConnections
268: // public List<List<String>> getTables(String schema)
269: // throws SQLException
270: // {
271: // List<List<String>> tables = null ;
272: // String tabs[] = dbmdh.getTables(schema) ;
273: // for (int icnt = 0 ; icnt < tabs.length ; icnt++ ) {
274: // tables.add(Arrays.asList(parseTableName(tabs[icnt]))) ;
275: // }
276: // String views[] = dbmdh.getViews(schema) ;
277: // for (int icnt = 0 ; icnt < views.length ; icnt++ ) {
278: // tables.add(Arrays.asList(parseTableName(tabs[icnt]))) ;
279: // }
280: // return tables;
281: // }
282:
283: /****
284: * Returns the a List of String objects of the primary key columns.
285: */
286: public Hashtable pkTable = new Hashtable(hashSizeForTables);
287:
288: // public List getPrimaryKeys(String fullTableName) throws SQLException
289: // {
290: // logInfo( dataSourceInfo.getName() + " getPrimaryKeys " + fullTableName ) ;
291:
292: // if ( dbmdh == null )
293: // initMetaData() ;
294:
295: // List primaryKeys = (List)pkTable.get(fullTableName) ;
296: // if ( primaryKeys != null )
297: // return primaryKeys ;
298:
299: // primaryKeys = new ArrayList();
300:
301: // String[] tableDesrip = parseTableName(fullTableName) ;
302:
303: // ResultSet rs = databaseMetaData.getPrimaryKeys(null, tableDesrip[0], tableDesrip[1] );
304: // if (rs != null) {
305: // String name;
306: // while (rs.next()) {
307: // name = rs.getString("COLUMN_NAME"); // NOI18N
308: // primaryKeys.add(name);
309: // }
310: // rs.close();
311: // }
312: // pkTable.put(fullTableName, primaryKeys) ;
313: // return primaryKeys ;
314: // }
315:
316: public List<String> getPrimaryKeys(String schema, String table)
317: throws SQLException {
318: logInfo(dataSourceInfo.getName() + " getPrimaryKeys " + schema
319: + "." + table);
320:
321: if (dbmdh == null)
322: initMetaData();
323:
324: String fullTableName = mergeTableName(schema, table);
325: List primaryKeys = (List) pkTable.get(fullTableName);
326: if (primaryKeys != null)
327: return primaryKeys;
328:
329: primaryKeys = new ArrayList();
330:
331: String[] tableDesrip = parseTableName(fullTableName);
332:
333: ResultSet rs = databaseMetaData.getPrimaryKeys(null, schema,
334: table);
335: if (rs != null) {
336: String name;
337: while (rs.next()) {
338: name = rs.getString("COLUMN_NAME"); // NOI18N
339: primaryKeys.add(name);
340: }
341: rs.close();
342: }
343: pkTable.put(fullTableName, primaryKeys);
344: return primaryKeys;
345: }
346:
347: /****
348: *
349: */
350: public Hashtable fkExportedTable = new Hashtable(hashSizeForTables);
351: public Hashtable fkImportedTable = new Hashtable(hashSizeForTables);
352:
353: // public List getForeignKeys(String fullTableName, boolean exported) throws SQLException {
354: // logInfo( dataSourceInfo.getName() + " getForeignKeys " + fullTableName ) ;
355: // if ( dbmdh == null ) initMetaData() ;
356: // Hashtable lookupTable ;
357: // if (exported ) {
358: // lookupTable = fkExportedTable ;
359: // } else {
360: // lookupTable = fkImportedTable ;
361: // }
362: // List keys = (List)lookupTable.get(fullTableName) ;
363: // if ( keys != null ) return keys ;
364:
365: // keys = new ArrayList() ;
366:
367: // String[] tableDesrip = parseTableName(fullTableName) ;
368:
369: // ResultSet rs =
370: // exported ?
371: // databaseMetaData.getExportedKeys(null, tableDesrip[0], tableDesrip[1] ) :
372: // databaseMetaData.getImportedKeys(null, tableDesrip[0], tableDesrip[1] );
373: // if (rs != null) {
374: // while (rs.next()) {
375: // String fschem = rs.getString("FKTABLE_SCHEM"); // NOI18N
376: // String pschem = rs.getString("PKTABLE_SCHEM"); // NOI18N
377: // String[] key = new String[] {
378: // ((fschem!=null) ? fschem+"." : "") + rs.getString("FKTABLE_NAME"), // NOI18N
379: // rs.getString("FKCOLUMN_NAME"), // NOI18N
380: // ((pschem!=null) ? pschem+"." : "") + rs.getString("PKTABLE_NAME"), // NOI18N
381: // rs.getString("PKCOLUMN_NAME") }; // NOI18N
382: // keys.add(key);
383: // }
384: // rs.close();
385: // }
386: // lookupTable.put(fullTableName, keys) ;
387:
388: // return keys ;
389: // }
390:
391: /*
392: public List getForeignKeys( String fullTableName ) throws SQLException {
393: List keys = getForeignKeys(fullTableName, true);
394: keys.addAll(getForeignKeys(fullTableName, false));
395: return keys ;
396: }
397: */
398:
399: /**
400: * New
401: */
402: public List<List<String>> getImportedKeys(String schema,
403: String table) throws SQLException {
404: return getForeignKeys(schema, table, false);
405: }
406:
407: /**
408: * New
409: */
410: public List<List<String>> getExportedKeys(String schema,
411: String table) throws SQLException {
412: return getForeignKeys(schema, table, true);
413: }
414:
415: /**
416: * New
417: */
418: private List<List<String>> getForeignKeys(String schema,
419: String table, boolean exported) throws SQLException {
420: logInfo(dataSourceInfo.getName() + " getForeign " + schema
421: + " " + table);
422:
423: if (dbmdh == null)
424: initMetaData();
425:
426: Hashtable lookupTable;
427: if (exported) {
428: lookupTable = fkExportedTable;
429: } else {
430: lookupTable = fkImportedTable;
431: }
432: String fullTableName = mergeTableName(schema, table);
433: List keys = (List) lookupTable.get(fullTableName);
434: if (keys != null)
435: return keys;
436:
437: keys = new ArrayList();
438: ResultSet rs = exported ? databaseMetaData.getExportedKeys(
439: null, schema, table) : databaseMetaData
440: .getImportedKeys(null, schema, table);
441: if (rs != null) {
442: while (rs.next()) {
443: String fschem = rs.getString("FKTABLE_SCHEM"); // NOI18N
444: String pschem = rs.getString("PKTABLE_SCHEM"); // NOI18N
445: List<String> key = Arrays.asList(
446: ((fschem != null) ? fschem + "." : "")
447: + rs.getString("FKTABLE_NAME"), // NOI18N
448: rs.getString("FKCOLUMN_NAME"), // NOI18N
449: ((pschem != null) ? pschem + "." : "")
450: + rs.getString("PKTABLE_NAME"), // NOI18N
451: rs.getString("PKCOLUMN_NAME")); // NOI18N
452: keys.add(key);
453: }
454: rs.close();
455: }
456: lookupTable.put(fullTableName, keys);
457:
458: return keys;
459: }
460:
461: // /**
462: // * Returns the imported key columns for this table -- i.e., the columns
463: // * whose value is a foreign key for another table. These columns are
464: // * displayed with a special icon in the Query Builder.
465: // */
466: // public Hashtable importKcTable = new Hashtable(hashSizeForTables) ;
467: // public List getImportedKeyColumns(String fullTableName)
468: // throws SQLException
469: // {
470: // logInfo( dataSourceInfo.getName() + " getImportedKeyColumns " + fullTableName ) ;
471: // if ( dbmdh == null )
472: // initMetaData() ;
473:
474: // List keys = (List)importKcTable.get(fullTableName) ;
475: // if ( keys != null )
476: // return keys ;
477:
478: // keys = new ArrayList();
479: // String[] tableDesrip = parseTableName(fullTableName) ;
480: // ResultSet rs = databaseMetaData.getImportedKeys(null, tableDesrip[0], tableDesrip[1] );
481: // if (rs != null) {
482: // String name;
483: // while (rs.next()) {
484: // name = rs.getString("FKCOLUMN_NAME"); // NOI18N
485: // keys.add(name);
486: // }
487: // rs.close();
488: // }
489: // importKcTable.put(fullTableName, keys) ;
490: // return keys ;
491: // }
492:
493: /**
494: * Returns the set of columns in the specified table
495: * as a List of String instances.
496: * If the specified table is null, return all columns.
497: */
498: private Hashtable columnNameTable = new Hashtable(hashSizeForTables);
499: private Hashtable allColumnsTable = new Hashtable(400);
500: private boolean allColumnsTableLoaded = false;
501:
502: // public List getColumnNames(String fullTableName) throws SQLException {
503: // logInfo( dataSourceInfo.getName() + " getColumnNames " + fullTableName ) ;
504: // if ( dbmdh == null )
505: // initMetaData() ;
506:
507: // List columnNames = (List)columnNameTable.get(fullTableName) ;
508: // logInfo( " cache hit="+ (columnNames!=null)) ;
509: // if (columnNames != null)
510: // return columnNames ;
511:
512: // columnNames = new ArrayList() ;
513:
514: // String[] tableDesrip = parseTableName(fullTableName) ;
515:
516: // ResultSet rs = databaseMetaData.getColumns(null, tableDesrip[0],tableDesrip[1], "%"); // NOI18N
517: // if (rs != null) {
518: // while (rs.next()) {
519: // columnNames.add(rs.getString("COLUMN_NAME")); // NOI18N
520: // }
521: // rs.close();
522:
523: // if ( Log.isLoggable()) {
524: // for (int j=0; j<columnNames.size(); j++)
525: // Log.log(" Column:" + (String) columnNames.get(j) ); // NOI18N
526: // }
527: // }
528: // logInfo( " getColumnNames loaded "+columnNames.size() ) ;
529: // columnNameTable.put(fullTableName, columnNames) ;
530: // for ( int i = 0 ; i < columnNames.size() ; i++) {
531: // allColumnsTable.put(columnNames.get(i),fullTableName) ;
532: // }
533: // return columnNames ;
534: // }
535:
536: // public java.util.Map getAllColumnNames() throws SQLException {
537: // if ( ! allColumnsTableLoaded ) {
538: // loadAllColumns() ;
539: // }
540: // return allColumnsTable ;
541: // }
542:
543: /*
544: * New
545: */
546: public List<String> getColumns(String schema, String table)
547: throws SQLException {
548: logInfo(dataSourceInfo.getName() + " getColumnsNames " + schema
549: + " " + table);
550: if (dbmdh == null)
551: initMetaData();
552:
553: String fullTableName = mergeTableName(schema, table);
554: List<String> columnNames = (List<String>) columnNameTable
555: .get(fullTableName);
556: logInfo(" cache hit=" + (columnNames != null));
557: if (columnNames != null)
558: return columnNames;
559:
560: columnNames = new ArrayList<String>();
561: ResultSet rs = databaseMetaData.getColumns(null, schema, table,
562: "%"); // NOI18N
563: if (rs != null) {
564: while (rs.next()) {
565: columnNames.add(rs.getString("COLUMN_NAME")); // NOI18N
566: }
567: rs.close();
568:
569: if (Log.isLoggable()) {
570: for (int j = 0; j < columnNames.size(); j++)
571: Log.log(" Column:"
572: + (String) columnNames.get(j)); // NOI18N
573: }
574: }
575: logInfo(" getColumnNames loaded " + columnNames.size());
576: columnNameTable.put(fullTableName, columnNames);
577: // for ( int i = 0 ; i < columnNames.size() ; i++) {
578: // allColumnsTable.put(columnNames.get(i),fullTableName) ;
579: // }
580: return columnNames;
581: }
582:
583: // /****
584: // * gets the tables that have cached colmumn names
585: // */
586: // public String[] getCachedColmnNameTables() throws SQLException {
587: // List ret = new ArrayList() ;
588: // java.util.Enumeration keys = columnNameTable.keys() ;
589: // while ( keys.hasMoreElements() ) {
590: // ret.add( (String)columnNameTable.get(keys.nextElement())) ;
591: // }
592: // return (String[])ret.toArray( new String[ret.size()]) ;
593: // }
594:
595: // private void loadAllColumns() throws SQLException {
596:
597: // logInfo( dataSourceInfo.getName() + " loading all columns" ) ;
598:
599: // List<List<String>> tabs = getTables() ;
600: // for ( int i = 0 ; i < tabs.size() ; i++ ) {
601: // String schema = tabs.get(i).get(0);
602: // String table = tabs.get(i).get(1);
603: // String fullTableName=
604: // ((schema==null) || schema.equals("")) ?
605: // table :
606: // schema + "." + table;
607: // getColumnNames( fullTableName ) ;
608: // // getColumnNames( (String)tabs.get(i)) ;
609: // }
610: // allColumnsTableLoaded = true ;
611: // logInfo( dataSourceInfo.getName() + " finished loading all columns" ) ;
612: // }
613:
614: String identifierQuoteString = null;
615:
616: public String getIdentifierQuoteString() throws SQLException {
617: logInfo(dataSourceInfo.getName() + " getIdentifierQuoteString ");
618: if (dbmdh == null)
619: initMetaData();
620: if (identifierQuoteString != null) {
621: return identifierQuoteString;
622: } else {
623: identifierQuoteString = databaseMetaData
624: .getIdentifierQuoteString();
625: return identifierQuoteString;
626: }
627: }
628:
629: /* ================================================================ */
630: /*****
631: * parse a full table name, e.g. Schema.Table or Table
632: * and returns an array where
633: * [0] = schema (or null if none found)
634: * [1] = table name.
635: */
636: private static String[] parseTableName(String fullTableName) {
637:
638: String[] retVal = new String[2];
639:
640: String[] table = fullTableName.split("\\."); // NOI18N
641: if (table.length > 1) {
642: retVal[0] = table[0];
643: retVal[1] = table[1];
644: } else {
645: retVal[0] = null;
646: retVal[1] = table[0];
647: }
648: return retVal;
649: }
650:
651: /*****
652: * The opposite of parseTableName -- combine a schema and table into schema.tableName,
653: * allowing for null or empty schema name
654: */
655: private static String mergeTableName(String schema, String table) {
656: return ((schema == null) || (schema.equals(""))) ? table
657: : schema + "." + table;
658: }
659:
660: private static final String LOGPREFIX = "DBCache: "; // NOI18N
661: private static ErrorManager err = ErrorManager
662: .getDefault()
663: .getInstance(
664: "org.netbeans.modules.visualweb.dataconnectivity.customizers"); // NOI18N
665:
666: private static void logInfo(String msg) {
667: err.log(ErrorManager.INFORMATIONAL, LOGPREFIX + msg);
668: }
669:
670: private boolean isLoggable() {
671: return err.isLoggable(ErrorManager.INFORMATIONAL);
672: }
673:
674: private boolean isLoggable(int sev) {
675: return err.isLoggable(sev);
676: }
677:
678: private void log(int sev, String msg) {
679: err.log(sev, msg);
680: }
681:
682: private static void logErrorInfo(String msg) {
683: err.log(ErrorManager.ERROR, LOGPREFIX + msg);
684: }
685:
686: }
|