http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DBReceiverJob.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/DBReceiverJob.java b/src/main/java/org/apache/log4j/db/DBReceiverJob.java new file mode 100644 index 0000000..1e29663 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/DBReceiverJob.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.scheduler.Job; +import org.apache.log4j.spi.ComponentBase; +import org.apache.log4j.spi.LocationInfo; +import org.apache.log4j.spi.LoggingEvent; +import org.apache.log4j.spi.ThrowableInformation; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Hashtable; +import java.util.Vector; + +/** + * Actual retrieval of data is made by the instance of DBReceiverJob associated + * with DBReceiver. + * + * @author Ceki Gülcü + */ +class DBReceiverJob extends ComponentBase implements Job { + + String sqlException = "SELECT trace_line FROM logging_event_exception where event_id=? ORDER by i ASC"; + String sqlProperties = "SELECT mapped_key, mapped_value FROM logging_event_property WHERE event_id=?"; + String sqlSelect = + "SELECT " + + "sequence_number, timestamp, rendered_message, logger_name, " + + "level_string, ndc, thread_name, reference_flag, " + + "caller_filename, caller_class, caller_method, caller_line, " + + "event_id " + + "FROM logging_event " + + "WHERE event_id > ? ORDER BY event_id ASC"; + + + long lastId = Short.MIN_VALUE; + + DBReceiver parentDBReceiver; + + DBReceiverJob(DBReceiver parent) { + parentDBReceiver = parent; + } + + public void execute() { + getLogger().debug("DBReceiverJob.execute() called"); + + Connection connection = null; + + try { + connection = parentDBReceiver.connectionSource.getConnection(); + PreparedStatement statement = connection.prepareStatement(sqlSelect); + statement.setLong(1, lastId); + ResultSet rs = statement.executeQuery(); + //rs.beforeFirst(); + + while (rs.next()) { + Logger logger = null; + long timeStamp = 0L; + String level = null; + String threadName = null; + Object message = null; + String ndc = null; + String className = null; + String methodName = null; + String fileName = null; + String lineNumber = null; + Hashtable properties = new Hashtable(); + + + //event.setSequenceNumber(rs.getLong(1)); + timeStamp = rs.getLong(2); + message = rs.getString(3); + logger = Logger.getLogger(rs.getString(4)); + level = rs.getString(5); + Level levelImpl = Level.toLevel(level.trim()); + + ndc = rs.getString(6); + threadName = rs.getString(7); + + short mask = rs.getShort(8); + + fileName = rs.getString(9); + className = rs.getString(10); + methodName = rs.getString(11); + lineNumber = rs.getString(12).trim(); + + LocationInfo locationInfo = null; + if (fileName.equals(LocationInfo.NA)) { + locationInfo = LocationInfo.NA_LOCATION_INFO; + } else { + locationInfo = new LocationInfo(fileName, className, + methodName, lineNumber); + } + + long id = rs.getLong(13); + //LogLog.info("Received event with id=" + id); + lastId = id; + + ThrowableInformation throwableInfo = null; + if ((mask & DBHelper.EXCEPTION_EXISTS) != 0) { + throwableInfo = getException(connection, id); + } + + LoggingEvent event = new LoggingEvent(logger.getName(), + logger, timeStamp, levelImpl, message, + threadName, + throwableInfo, + ndc, + locationInfo, + properties); + + + // Scott asked for this info to be + event.setProperty("log4jid", Long.toString(id)); + + if ((mask & DBHelper.PROPERTIES_EXIST) != 0) { + getProperties(connection, id, event); + } + + + + + if (!parentDBReceiver.isPaused()) { + parentDBReceiver.doPost(event); + } + } // while + statement.close(); + statement = null; + } catch (SQLException sqle) { + getLogger().error("Problem receiving events", sqle); + } finally { + closeConnection(connection); + } + } + + void closeConnection(Connection connection) { + if (connection != null) { + try { + //LogLog.warn("closing the connection. ", new Exception("x")); + connection.close(); + } catch (SQLException sqle) { + // nothing we can do here + } + } + } + + /** + * Retrieve the event properties from the logging_event_property table. + * + * @param connection + * @param id + * @param event + * @throws SQLException + */ + void getProperties(Connection connection, long id, LoggingEvent event) + throws SQLException { + + PreparedStatement statement = connection.prepareStatement(sqlProperties); + try { + statement.setLong(1, id); + ResultSet rs = statement.executeQuery(); + + while (rs.next()) { + String key = rs.getString(1); + String value = rs.getString(2); + event.setProperty(key, value); + } + } finally { + statement.close(); + } + } + + /** + * Retrieve the exception string representation from the + * logging_event_exception table. + * + * @param connection + * @param id + * @throws SQLException + */ + ThrowableInformation getException(Connection connection, long id) + throws SQLException { + + PreparedStatement statement = null; + + try { + statement = connection.prepareStatement(sqlException); + statement.setLong(1, id); + ResultSet rs = statement.executeQuery(); + + Vector v = new Vector(); + + while (rs.next()) { + //int i = rs.getShort(1); + v.add(rs.getString(1)); + } + + int len = v.size(); + String[] strRep = new String[len]; + for (int i = 0; i < len; i++) { + strRep[i] = (String) v.get(i); + } + // we've filled strRep, we now attach it to the event + return new ThrowableInformation(strRep); + } finally { + if (statement != null) { + statement.close(); + } + } + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java b/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java new file mode 100644 index 0000000..d5975ee --- /dev/null +++ b/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db; + + +import org.apache.log4j.xml.DOMConfigurator; +import org.apache.log4j.xml.UnrecognizedElementHandler; +import org.w3c.dom.Element; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + + +/** + * The DataSourceConnectionSource is an implementation of {@link ConnectionSource} + * that obtains the Connection in the recommended JDBC manner based on + * a {@link javax.sql.DataSource DataSource}. + * <p> + * + * @author Ray DeCampo + * @author Ceki Gülcü + */ +public class DataSourceConnectionSource extends ConnectionSourceSkeleton + implements UnrecognizedElementHandler { + + private DataSource dataSource; + + + public void activateOptions() { + //LogLog.debug("**********DataSourceConnectionSource.activateOptions called"); + if (dataSource == null) { + getLogger().warn("WARNING: No data source specified"); + } else { + Connection connection = null; + try { + connection = getConnection(); + } catch(SQLException se) { + getLogger().warn("Could not get a connection to discover the dialect to use.", se); + } + if(connection != null) { + discoverConnnectionProperties(); + } + if(!supportsGetGeneratedKeys() && getSQLDialectCode() == ConnectionSource.UNKNOWN_DIALECT) { + getLogger().warn("Connection does not support GetGeneratedKey method and could not discover the dialect."); + } + } + } + + /** + * @see org.apache.log4j.db.ConnectionSource#getConnection() + */ + public Connection getConnection() throws SQLException { + if (dataSource == null) { + getLogger().error("WARNING: No data source specified"); + return null; + } + + if (getUser() == null) { + return dataSource.getConnection(); + } else { + return dataSource.getConnection(getUser(), getPassword()); + } + } + + public DataSource getDataSource() { + return dataSource; + } + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + /** + * @{inheritDoc} + */ + public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception { + if ("dataSource".equals(element.getNodeName())) { + Object instance = + DOMConfigurator.parseElement(element, props, DataSource.class); + if (instance instanceof DataSource) { + setDataSource((DataSource) instance); + } + return true; + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java b/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java new file mode 100644 index 0000000..9bfdf65 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + + +/** + * The DriverManagerConnectionSource is an implementation of {@link ConnectionSource} + * that obtains the Connection in the traditional JDBC manner based on the + * connection URL. + * <p> + * Note that this class will establish a new Connection for each call to + * {@link #getConnection()}. It is recommended that you either use a JDBC + * driver that natively supported Connection pooling or that you create + * your own implementation of {@link ConnectionSource} that taps into whatever + * pooling mechanism you are already using. (If you have access to a JNDI + * implementation that supports {@link javax.sql.DataSource}s, e.g. within + * a J2EE application server, see {@link JNDIConnectionSource}). See + * <a href="#dbcp">below</a> for a configuration example that uses the + * <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a> + * package from Apache. + * <p> + * Sample configuration:<br> + * <pre> + * <connectionSource class="org.apache.log4j.jdbc.DriverManagerConnectionSource"> + * <param name="driver" value="com.mysql.jdbc.Driver" /> + * <param name="url" value="jdbc:mysql://localhost:3306/mydb" /> + * <param name="username" value="myUser" /> + * <param name="password" value="myPassword" /> + * </connectionSource> + * </pre> + * <p> + * <a name="dbcp">If</a> you do not have another connection pooling mechanism + * built into your application, you can use the + * <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a> + * package from Apache:<br> + * <pre> + * <connectionSource class="org.apache.log4j.jdbc.DriverManagerConnectionSource"> + * <param name="driver" value="org.apache.commons.dbcp.PoolingDriver" /> + * <param name="url" value="jdbc:apache:commons:dbcp:/myPoolingDriver" /> + * </connectionSource> + * </pre> + * Then the configuration information for the commons-dbcp package goes into + * the file myPoolingDriver.jocl and is placed in the classpath. See the + * <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a> + * documentation for details. + * + * @author <a href="mailto:[email protected]">Ray DeCampo</a> + */ +public class DriverManagerConnectionSource extends ConnectionSourceSkeleton { + private String driverClass = null; + private String url = null; + + public void activateOptions() { + try { + if (driverClass != null) { + Class.forName(driverClass); + discoverConnnectionProperties(); + } else { + getLogger().error( + "WARNING: No JDBC driver specified for log4j DriverManagerConnectionSource."); + } + } catch (final ClassNotFoundException cnfe) { + getLogger().error("Could not load JDBC driver class: " + driverClass, cnfe); + } + } + + + /** + * @see org.apache.log4j.db.ConnectionSource#getConnection() + */ + public Connection getConnection() throws SQLException { + if (getUser() == null) { + return DriverManager.getConnection(url); + } else { + return DriverManager.getConnection(url, getUser(), getPassword()); + } + } + + + /** + * Returns the url. + * @return String + */ + public String getUrl() { + return url; + } + + + /** + * Sets the url. + * @param url The url to set + */ + public void setUrl(String url) { + this.url = url; + } + + + /** + * Returns the name of the driver class. + * @return String + */ + public String getDriverClass() { + return driverClass; + } + + + /** + * Sets the driver class. + * @param driverClass The driver class to set + */ + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java b/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java new file mode 100644 index 0000000..7073738 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.log4j.db; + +import java.sql.Connection; +import java.sql.SQLException; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +// PortableRemoteObject was introduced in JDK 1.3. We won't use it. +// import javax.rmi.PortableRemoteObject; +import javax.sql.DataSource; + + +/** + * The <id>JNDIConnectionSource</id> is an implementation of + * {@link ConnectionSource} that obtains a {@link javax.sql.DataSource} from a + * JNDI provider and uses it to obtain a {@link java.sql.Connection}. It is + * primarily designed to be used inside of J2EE application servers or + * application server clients, assuming the application server supports remote + * access of {@link javax.sql.DataSource}s. In this way one can take + * advantage of connection pooling and whatever other goodies the application + * server provides. + * <p> + * Sample configuration:<br> + * <pre> + * <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource"> + * <param name="jndiLocation" value="jdbc/MySQLDS" /> + * </connectionSource> + * </pre> + * <p> + * Sample configuration (with username and password):<br> + * <pre> + * <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource"> + * <param name="jndiLocation" value="jdbc/MySQLDS" /> + * <param name="username" value="myUser" /> + * <param name="password" value="myPassword" /> + * </connectionSource> + * </pre> + * <p> + * Note that this class will obtain an {@link javax.naming.InitialContext} + * using the no-argument constructor. This will usually work when executing + * within a J2EE environment. When outside the J2EE environment, make sure + * that you provide a jndi.properties file as described by your JNDI + * provider's documentation. + * + * @author <a href="mailto:[email protected]">Ray DeCampo</a> + */ +public class JNDIConnectionSource + extends ConnectionSourceSkeleton { + private String jndiLocation = null; + private DataSource dataSource = null; + + /** + * @see org.apache.log4j.spi.OptionHandler#activateOptions() + */ + public void activateOptions() { + if (jndiLocation == null) { + getLogger().error("No JNDI location specified for JNDIConnectionSource."); + } + + discoverConnnectionProperties(); + + } + + /** + * @see org.apache.log4j.db.ConnectionSource#getConnection() + */ + public Connection getConnection() + throws SQLException { + Connection conn = null; + try { + + if(dataSource == null) { + dataSource = lookupDataSource(); + } + if (getUser() == null) { + conn = dataSource.getConnection(); + } else { + conn = dataSource.getConnection(getUser(), getPassword()); + } + } catch (final NamingException ne) { + getLogger().error("Error while getting data source", ne); + throw new SQLException("NamingException while looking up DataSource: " + ne.getMessage()); + } catch (final ClassCastException cce) { + getLogger().error("ClassCastException while looking up DataSource.", cce); + throw new SQLException("ClassCastException while looking up DataSource: " + cce.getMessage()); + } + + return conn; + } + + /** + * Returns the jndiLocation. + * @return String + */ + public String getJndiLocation() { + return jndiLocation; + } + + + /** + * Sets the jndiLocation. + * @param jndiLocation The jndiLocation to set + */ + public void setJndiLocation(String jndiLocation) { + this.jndiLocation = jndiLocation; + } + + + private DataSource lookupDataSource() + throws NamingException, SQLException { + DataSource ds; + Context ctx = new InitialContext(); + Object obj = ctx.lookup(jndiLocation); + + // PortableRemoteObject was introduced in JDK 1.3. We won't use it. + //ds = (DataSource)PortableRemoteObject.narrow(obj, DataSource.class); + ds = (DataSource) obj; + + if (ds == null) { + throw new SQLException("Failed to obtain data source from JNDI location " + jndiLocation); + } else { + return ds; + } + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java b/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java new file mode 100644 index 0000000..164a125 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db.dialect; + +/** + * The HSQLDB dialect. + * + * @author <a href="http://www.qos.ch/log4j/">Ceki Gülcü</a> +*/ +public class HSQLDBDialect implements SQLDialect { + public static final String SELECT_CURRVAL = "CALL IDENTITY()"; + + public String getSelectInsertId() { + return SELECT_CURRVAL; + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java new file mode 100644 index 0000000..08f4fc3 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db.dialect; + +/** +* The MS SQL Server dialect is untested. +* +* Note that the dialect is not needed if your JDBC driver supports +* the getGeneratedKeys method introduced in JDBC 3.0 specification. +* +* @author James Stauffer +*/ +public class MsSQLDialect implements SQLDialect { + public static final String SELECT_CURRVAL = "SELECT @@identity id"; + + public String getSelectInsertId() { + return SELECT_CURRVAL; + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java new file mode 100644 index 0000000..c1a63cd --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db.dialect; + +/** + * + * + * @author Ceki + * + */ +public class MySQLDialect implements SQLDialect { + public static final String SELECT_LAST_INSERT_ID = "SELECT LAST_INSERT_ID()"; + + public String getSelectInsertId() { + return SELECT_LAST_INSERT_ID; + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java b/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java new file mode 100644 index 0000000..1714f1f --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db.dialect; + +/** + * The Oracle dialect. Tested successfully on Oracle9i Release 9.2.0.3.0 by + * James Stauffer. + * + * @author Ceki Gülcü + */ +public class OracleDialect implements SQLDialect { + public static final String SELECT_CURRVAL = "SELECT logging_event_id_seq.currval from dual"; + + public String getSelectInsertId() { + return SELECT_CURRVAL; + } + +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java new file mode 100644 index 0000000..dde4ff9 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db.dialect; + + +/** + * + * @author ceki + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public class PostgreSQLDialect + implements SQLDialect { + public static final String SELECT_CURRVAL = "SELECT currval('logging_event_id_seq')"; + + public String getSelectInsertId() { + return SELECT_CURRVAL; + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java new file mode 100644 index 0000000..291283f --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.log4j.db.dialect; + +/** + * @author ceki + * + */ +public interface SQLDialect { + + public String getSelectInsertId(); + +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java b/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java new file mode 100644 index 0000000..44ba75e --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.log4j.db.dialect; + +/** + * The Sybase dialect. + * +*/ +public class SybaseDialect implements SQLDialect { + public static final String SELECT_CURRVAL = "select @@identity"; + + public String getSelectInsertId() { + return SELECT_CURRVAL; + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/Util.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/Util.java b/src/main/java/org/apache/log4j/db/dialect/Util.java new file mode 100644 index 0000000..5d60b12 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/Util.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.db.dialect; + +import org.apache.log4j.db.ConnectionSource; +import org.apache.log4j.spi.ComponentBase; + +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + + +/** + * + * @author Ceki Gulcu + * + */ +public class Util extends ComponentBase { + private static final String POSTGRES_PART = "postgresql"; + private static final String MYSQL_PART = "mysql"; + private static final String ORACLE_PART = "oracle"; + //private static final String MSSQL_PART = "mssqlserver4"; + private static final String MSSQL_PART = "microsoft"; + private static final String HSQL_PART = "hsql"; + + public static int discoverSQLDialect(DatabaseMetaData meta) { + int dialectCode = 0; + + try { + + String dbName = meta.getDatabaseProductName().toLowerCase(); + + if (dbName.indexOf(POSTGRES_PART) != -1) { + return ConnectionSource.POSTGRES_DIALECT; + } else if (dbName.indexOf(MYSQL_PART) != -1) { + return ConnectionSource.MYSQL_DIALECT; + } else if (dbName.indexOf(ORACLE_PART) != -1) { + return ConnectionSource.ORACLE_DIALECT; + } else if (dbName.indexOf(MSSQL_PART) != -1) { + return ConnectionSource.MSSQL_DIALECT; + } else if (dbName.indexOf(HSQL_PART) != -1) { + return ConnectionSource.HSQL_DIALECT; + } else { + return ConnectionSource.UNKNOWN_DIALECT; + } + } catch (SQLException sqle) { + // we can't do much here + } + + return dialectCode; + } + + public static SQLDialect getDialectFromCode(int dialectCode) { + SQLDialect sqlDialect = null; + + switch (dialectCode) { + case ConnectionSource.POSTGRES_DIALECT: + sqlDialect = new PostgreSQLDialect(); + + break; + case ConnectionSource.MYSQL_DIALECT: + sqlDialect = new MySQLDialect(); + + break; + case ConnectionSource.ORACLE_DIALECT: + sqlDialect = new OracleDialect(); + + break; + case ConnectionSource.MSSQL_DIALECT: + sqlDialect = new MsSQLDialect(); + + break; + case ConnectionSource.HSQL_DIALECT: + sqlDialect = new HSQLDBDialect(); + + break; + } + return sqlDialect; + } + + /** + * This method handles cases where the + * {@link DatabaseMetaData#supportsGetGeneratedKeys} method is missing in the + * JDBC driver implementation. + */ + public boolean supportsGetGeneratedKeys(DatabaseMetaData meta) { + try { + // + // invoking JDK 1.4 method by reflection + // + return ((Boolean) DatabaseMetaData.class.getMethod("supportsGetGeneratedKeys", null).invoke(meta, null)).booleanValue(); + } catch(Throwable e) { + getLogger().info("Could not call supportsGetGeneratedKeys method. This may be recoverable"); + return false; + } + } + +/** + * This method handles cases where the + * {@link DatabaseMetaData#supportsBatchUpdates} method is missing in the + * JDBC driver implementation. + */ + public boolean supportsBatchUpdates(DatabaseMetaData meta) { + try { + return meta.supportsBatchUpdates(); + } catch(Throwable e) { + getLogger().info("Missing DatabaseMetaData.supportsBatchUpdates method."); + return false; + } + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/db2.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/db2.sql b/src/main/java/org/apache/log4j/db/dialect/db2.sql new file mode 100644 index 0000000..47d2164 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/db2.sql @@ -0,0 +1,64 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and +# org.apache.log4j.db.DBReceiver. +# +# It is intended for IBM DB2 databases. +# +# WARNING WARNING WARNING WARNING +# ================================= +# This SQL script has not been tested on an actual DB2 +# instance. It may contain errors or even invalid SQL +# statements. + +DROP TABLE logging_event_property; +DROP TABLE logging_event_exception; +DROP TABLE logging_event; + +CREATE TABLE logging_event + ( + sequence_number BIGINT NOT NULL, + timestamp BIGINT NOT NULL, + rendered_message VARCHAR(4000) NOT NULL, + logger_name VARCHAR(254) NOT NULL, + level_string VARCHAR(254) NOT NULL, + ndc VARCHAR(4000), + thread_name VARCHAR(254), + reference_flag SMALLINT, + caller_filename VARCHAR(254) NOT NULL, + caller_class VARCHAR(254) NOT NULL, + caller_method VARCHAR(254) NOT NULL, + caller_line CHAR(4) NOT NULL, + event_id INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1) + ); + +CREATE TABLE logging_event_property + ( + event_id INTEGER NOT NULL, + mapped_key VARCHAR(254) NOT NULL, + mapped_value VARCHAR(1024), + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); + +CREATE TABLE logging_event_exception + ( + event_id INTEGER NOT NULL, + i SMALLINT NOT NULL, + trace_line VARCHAR(254) NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/db2l.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/db2l.sql b/src/main/java/org/apache/log4j/db/dialect/db2l.sql new file mode 100644 index 0000000..0f91315 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/db2l.sql @@ -0,0 +1,61 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and +# org.apache.log4j.db.DBReceiver. +# +# It is intended for PostgreSQL databases. + +DROP TABLE logging_event_property; +DROP TABLE logging_event_exception; +DROP TABLE logging_event; + + +CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1; + + +CREATE TABLE logging_event + ( + sequence_number BIGINT NOT NULL, + timestamp BIGINT NOT NULL, + rendered_message TEXT NOT NULL, + logger_name VARCHAR(254) NOT NULL, + level_string VARCHAR(254) NOT NULL, + ndc TEXT, + thread_name VARCHAR(254), + reference_flag SMALLINT, + caller_filename VARCHAR(254) NOT NULL, + caller_class VARCHAR(254) NOT NULL, + caller_method VARCHAR(254) NOT NULL, + caller_line CHAR(4) NOT NULL, + event_id INT IDENTITY GENERATED ALWAYS PRIMARY KEY + ); + +CREATE TABLE logging_event_property + ( + event_id INT NOT NULL, + mapped_key VARCHAR(254) NOT NULL, + mapped_value VARCHAR(1024), + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); + +CREATE TABLE logging_event_exception + ( + event_id INT NOT NULL, + i SMALLINT NOT NULL, + trace_line VARCHAR(254) NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql b/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql new file mode 100644 index 0000000..50f8f78 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql @@ -0,0 +1,60 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// This SQL script creates the required tables by +// org.apache.log4j.db.DBAppender and org.apache.log4j.db.DBReceiver. +// +// It is intended for HSQLDB. +// + +DROP TABLE logging_event_exception IF EXISTS; +DROP TABLE logging_event_property IF EXISTS; +DROP TABLE logging_event IF EXISTS; + + +CREATE TABLE logging_event + ( + sequence_number BIGINT NOT NULL, + timestamp BIGINT NOT NULL, + rendered_message LONGVARCHAR NOT NULL, + logger_name VARCHAR NOT NULL, + level_string VARCHAR NOT NULL, + ndc LONGVARCHAR, + thread_name VARCHAR, + reference_flag SMALLINT, + caller_filename VARCHAR, + caller_class VARCHAR, + caller_method VARCHAR, + caller_line CHAR(4), + event_id INT NOT NULL IDENTITY + ); + + +CREATE TABLE logging_event_property + ( + event_id INT NOT NULL, + mapped_key VARCHAR(254) NOT NULL, + mapped_value LONGVARCHAR, + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); + +CREATE TABLE logging_event_exception + ( + event_id INT NOT NULL, + i SMALLINT NOT NULL, + trace_line VARCHAR NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/mssql.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/mssql.sql b/src/main/java/org/apache/log4j/db/dialect/mssql.sql new file mode 100644 index 0000000..d87e0a0 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/mssql.sql @@ -0,0 +1,61 @@ +-- Licensed to the Apache Software Foundation (ASF) under one or more +-- contributor license agreements. See the NOTICE file distributed with +-- this work for additional information regarding copyright ownership. +-- The ASF licenses this file to You under the Apache License, Version 2.0 +-- (the "License"); you may not use this file except in compliance with +-- the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- +-- This SQL script creates the required tables by org.apache.log4j.db.DBAppender and +-- org.apache.log4j.db.DBReceiver. +-- +-- It is intended for MS SQL Server databases. This has been tested with version 7.0. + +DROP TABLE logging_event_property +DROP TABLE logging_event_exception +DROP TABLE logging_event + +CREATE TABLE logging_event + ( + sequence_number DECIMAL(20) NOT NULL, + timestamp DECIMAL(20) NOT NULL, + rendered_message VARCHAR(4000) NOT NULL, + logger_name VARCHAR(254) NOT NULL, + level_string VARCHAR(254) NOT NULL, + ndc VARCHAR(4000), + thread_name VARCHAR(254), + reference_flag SMALLINT, + caller_filename VARCHAR(254) NOT NULL, + caller_class VARCHAR(254) NOT NULL, + caller_method VARCHAR(254) NOT NULL, + caller_line CHAR(4) NOT NULL, + event_id INT NOT NULL identity, + PRIMARY KEY(event_id) + ) + +CREATE TABLE logging_event_property + ( + event_id INT NOT NULL, + mapped_key VARCHAR(254) NOT NULL, + mapped_value VARCHAR(1024), + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ) + +CREATE TABLE logging_event_exception + ( + event_id INT NOT NULL, + i SMALLINT NOT NULL, + trace_line VARCHAR(254) NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ) + http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/mysql.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/mysql.sql b/src/main/java/org/apache/log4j/db/dialect/mysql.sql new file mode 100644 index 0000000..e3a2be1 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/mysql.sql @@ -0,0 +1,71 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and +# org.apache.log4j.db.DBReceiver. +# +# It is intended for MySQL databases. It has been tested on MySQL 4.1.1 with +# INNODB tables. + + +BEGIN; +DROP TABLE IF EXISTS logging_event_property; +DROP TABLE IF EXISTS logging_event_exception; +DROP TABLE IF EXISTS logging_event; +COMMIT; + + +BEGIN; +CREATE TABLE logging_event + ( + sequence_number BIGINT NOT NULL, + timestamp BIGINT NOT NULL, + rendered_message TEXT NOT NULL, + logger_name VARCHAR(254) NOT NULL, + level_string VARCHAR(254) NOT NULL, + ndc TEXT, + thread_name VARCHAR(254), + reference_flag SMALLINT, + caller_filename VARCHAR(254) NOT NULL, + caller_class VARCHAR(254) NOT NULL, + caller_method VARCHAR(254) NOT NULL, + caller_line CHAR(4) NOT NULL, + event_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY + ); +COMMIT; + +BEGIN; +CREATE TABLE logging_event_property + ( + event_id INT NOT NULL, + mapped_key VARCHAR(254) NOT NULL, + mapped_value TEXT, + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); +COMMIT; + +BEGIN; +CREATE TABLE logging_event_exception + ( + event_id INT NOT NULL, + i SMALLINT NOT NULL, + trace_line VARCHAR(254) NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); +COMMIT; http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/oracle.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/oracle.sql b/src/main/java/org/apache/log4j/db/dialect/oracle.sql new file mode 100644 index 0000000..84bf9e5 --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/oracle.sql @@ -0,0 +1,77 @@ +-- Licensed to the Apache Software Foundation (ASF) under one or more +-- contributor license agreements. See the NOTICE file distributed with +-- this work for additional information regarding copyright ownership. +-- The ASF licenses this file to You under the Apache License, Version 2.0 +-- (the "License"); you may not use this file except in compliance with +-- the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- +-- This SQL script creates the required tables by org.apache.log4j.db.DBAppender and +-- org.apache.log4j.db.DBReceiver. +-- +-- It is intended for Oracle databases. + +-- Tested successfully on Oracle9i Release 9.2.0.3.0 by James Stauffer +-- Tested successfully on Oracle9i Release by Elias Ross + +-- The following lines are useful in cleaning any previous tables + +--drop TRIGGER logging_event_id_seq_trig; +--drop SEQUENCE logging_event_id_seq; +--drop table logging_event_property; +--drop table logging_event_exception; +--drop table logging_event; + +CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START WITH 1; + +CREATE TABLE logging_event + ( + sequence_number NUMBER(20) NOT NULL, + timestamp NUMBER(20) NOT NULL, + rendered_message VARCHAR2(4000) NOT NULL, + logger_name VARCHAR2(254) NOT NULL, + level_string VARCHAR2(254) NOT NULL, + ndc VARCHAR2(4000), + thread_name VARCHAR2(254), + reference_flag NUMBER(5), + caller_filename VARCHAR2(254) NOT NULL, + caller_class VARCHAR2(254) NOT NULL, + caller_method VARCHAR2(254) NOT NULL, + caller_line CHAR(4) NOT NULL, + event_id NUMBER(10) PRIMARY KEY + ); + +CREATE OR REPLACE TRIGGER logging_event_id_seq_trig +BEFORE INSERT ON logging_event +FOR EACH ROW +BEGIN + SELECT logging_event_id_seq.nextval + INTO :new.sequence_number FROM dual; +END; + +CREATE TABLE logging_event_property + ( + event_id NUMBER(10) NOT NULL, + mapped_key VARCHAR2(254) NOT NULL, + mapped_value VARCHAR2(1024), + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); + +CREATE TABLE logging_event_exception + ( + event_id NUMBER(10) NOT NULL, + i NUMBER(5) NOT NULL, + trace_line VARCHAR2(254) NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); + http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/postgresql.sql ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/dialect/postgresql.sql b/src/main/java/org/apache/log4j/db/dialect/postgresql.sql new file mode 100644 index 0000000..c38757b --- /dev/null +++ b/src/main/java/org/apache/log4j/db/dialect/postgresql.sql @@ -0,0 +1,63 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +## This SQL script creates the required tables by org.apache.log4j.db.DBAppender and +# org.apache.log4j.db.DBReceiver. +# +# It is intended for PostgreSQL databases. + +DROP TABLE logging_event_property; +DROP TABLE logging_event_exception; +DROP SEQUENCE logging_event_id_seq; +DROP TABLE logging_event; + + +CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1; + + +CREATE TABLE logging_event + ( + sequence_number BIGINT NOT NULL, + timestamp BIGINT NOT NULL, + rendered_message TEXT NOT NULL, + logger_name VARCHAR(254) NOT NULL, + level_string VARCHAR(254) NOT NULL, + ndc TEXT, + thread_name VARCHAR(254), + reference_flag SMALLINT, + caller_filename VARCHAR(254) NOT NULL, + caller_class VARCHAR(254) NOT NULL, + caller_method VARCHAR(254) NOT NULL, + caller_line CHAR(4) NOT NULL, + event_id INT DEFAULT nextval('logging_event_id_seq') PRIMARY KEY + ); + +CREATE TABLE logging_event_property + ( + event_id INT NOT NULL, + mapped_key VARCHAR(254) NOT NULL, + mapped_value VARCHAR(1024), + PRIMARY KEY(event_id, mapped_key), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); + +CREATE TABLE logging_event_exception + ( + event_id INT NOT NULL, + i SMALLINT NOT NULL, + trace_line VARCHAR(254) NOT NULL, + PRIMARY KEY(event_id, i), + FOREIGN KEY (event_id) REFERENCES logging_event(event_id) + ); http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/package.html ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/db/package.html b/src/main/java/org/apache/log4j/db/package.html new file mode 100644 index 0000000..55652fb --- /dev/null +++ b/src/main/java/org/apache/log4j/db/package.html @@ -0,0 +1,36 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<html> +<body> + +<p>The org.apache.log4j.db package provides means to append logging events +into various databases. The persisted data can be later read back using +{@link org.apache.log4j.db.DBReceiver}. +</p> + +<p>Most popular database systems, such as PostgreSQL, MySQL, Oracle, DB2 and MsSQL +are supported. +</p> + +<p>Just as importantly, the way for obtaining JDBC connections is pluggable. Connections can +be obtained through the tradinal way of DriverManager, or alternatively as a DataSource. +A DataSource can be instantiated directly or it can obtained through JNDI. +</p> + +</body> +</html> http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/helpers/Constants.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/helpers/Constants.java b/src/main/java/org/apache/log4j/helpers/Constants.java new file mode 100644 index 0000000..dbbbe59 --- /dev/null +++ b/src/main/java/org/apache/log4j/helpers/Constants.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.helpers; + + +/** + * Constants used internally throughout log4j. + * + */ +public interface Constants { + + /** + * log4j package name string literal. + */ + String LOG4J_PACKAGE_NAME = "org.apache.log4j"; + + /** + * The name of the default repository is "default" (without the quotes). + */ + String DEFAULT_REPOSITORY_NAME = "default"; + + /** + * application string literal. + */ + String APPLICATION_KEY = "application"; + /** + * hostname string literal. + */ + String HOSTNAME_KEY = "hostname"; + /** + * receiver string literal. + */ + String RECEIVER_NAME_KEY = "receiver"; + /** + * log4jid string literal. + */ + String LOG4J_ID_KEY = "log4jid"; + /** + * time stamp pattern string literal. + */ + String TIMESTAMP_RULE_FORMAT = "yyyy/MM/dd HH:mm:ss"; + + /** + * The default property file name for automatic configuration. + */ + String DEFAULT_CONFIGURATION_FILE = "log4j.properties"; + /** + * The default XML configuration file name for automatic configuration. + */ + String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml"; + /** + * log4j.configuration string literal. + */ + String DEFAULT_CONFIGURATION_KEY = "log4j.configuration"; + /** + * log4j.configuratorClass string literal. + */ + String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass"; + + /** + * JNDI context name string literal. + */ + String JNDI_CONTEXT_NAME = "java:comp/env/log4j/context-name"; + + /** + * TEMP_LIST_APPENDER string literal. + */ + String TEMP_LIST_APPENDER_NAME = "TEMP_LIST_APPENDER"; + /** + * TEMP_CONSOLE_APPENDER string literal. + */ + String TEMP_CONSOLE_APPENDER_NAME = "TEMP_CONSOLE_APPENDER"; + /** + * Codes URL string literal. + */ + String CODES_HREF = + "http://logging.apache.org/log4j/docs/codes.html"; + + + /** + * ABSOLUTE string literal. + */ + String ABSOLUTE_FORMAT = "ABSOLUTE"; + /** + * SimpleTimePattern for ABSOLUTE. + */ + String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS"; + + /** + * SimpleTimePattern for ABSOLUTE. + */ + String SIMPLE_TIME_PATTERN = "HH:mm:ss"; + + /** + * DATE string literal. + */ + String DATE_AND_TIME_FORMAT = "DATE"; + /** + * SimpleTimePattern for DATE. + */ + String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS"; + + /** + * ISO8601 string literal. + */ + String ISO8601_FORMAT = "ISO8601"; + /** + * SimpleTimePattern for ISO8601. + */ + String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS"; +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/helpers/MessageFormatter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/helpers/MessageFormatter.java b/src/main/java/org/apache/log4j/helpers/MessageFormatter.java new file mode 100644 index 0000000..8c77da1 --- /dev/null +++ b/src/main/java/org/apache/log4j/helpers/MessageFormatter.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.helpers; + + +/** + * Formats messages according to very simple rules. + * See {@link #format(String,Object)} and + * {@link #format(String,Object,Object)} for more details. + * + * @author Ceki Gülcü + */ +public final class MessageFormatter { + /** + * Private formatter since all methods and members are static. + */ + private MessageFormatter() { + super(); + } + + /** + * Start of replacement block. + */ + private static final char DELIM_START = '{'; + /** + * End of replacement block. + */ + private static final char DELIM_STOP = '}'; + + /** + * Performs single argument substitution for the 'messagePattern' passed as + * parameter. + * <p/> + * For example, <code>MessageFormatter.format("Hi {}.", "there");</code> + * will return the string "Hi there.". + * <p/> + * The {} pair is called the formatting element. It serves to designate the + * location where the argument needs to be inserted within the pattern. + * + * @param messagePattern + * The message pattern which will be parsed and formatted + * @param argument + * The argument to be inserted instead of the formatting element + * @return The formatted message + */ + public static String format(final String messagePattern, + final Object argument) { + int j = messagePattern.indexOf(DELIM_START); + int len = messagePattern.length(); + char escape = 'x'; + + // if there are no { characters or { is the last character + // then we just return messagePattern + if (j == -1 || (j + 1 == len)) { + return messagePattern; + } else { + char delimStop = messagePattern.charAt(j + 1); + if (j > 0) { + escape = messagePattern.charAt(j - 1); + } + if ((delimStop != DELIM_STOP) || (escape == '\\')) { + // invalid DELIM_START/DELIM_STOP pair or espace character is + // present + return messagePattern; + } else { + StringBuffer sbuf = new StringBuffer(len + 20); + sbuf.append(messagePattern.substring(0, j)); + sbuf.append(argument); + sbuf.append(messagePattern.substring(j + 2)); + return sbuf.toString(); + } + } + } + + /** + * /** + * Performs a two argument substitution for the 'messagePattern' passed as + * parameter. + * <p/> + * For example, <code>MessageFormatter.format("Hi {}. My name is {}.", + * "there", "David");</code> will return the string + * "Hi there. My name is David.". + * <p/> + * The '{}' pair is called a formatting element. It serves to designate the + * location where the arguments need to be inserted within + * the message pattern. + * + * @param messagePattern + * The message pattern which will be parsed and formatted + * @param arg1 + * The first argument to replace the first formatting element + * @param arg2 + * The second argument to replace the second formatting element + * @return The formatted message + */ + public static String format(final String messagePattern, + final Object arg1, + final Object arg2) { + int i = 0; + int len = messagePattern.length(); + + StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50); + + for (int l = 0; l < 2; l++) { + int j = messagePattern.indexOf(DELIM_START, i); + + if (j == -1 || (j + 1 == len)) { + // no more variables + if (i == 0) { // this is a simple string + return messagePattern; + } else { + // add the tail string which contains no variables + // and return the result. + sbuf.append(messagePattern.substring(i, + messagePattern.length())); + return sbuf.toString(); + } + } else { + char delimStop = messagePattern.charAt(j + 1); + if ((delimStop != DELIM_STOP)) { + // invalid DELIM_START/DELIM_STOP pair + sbuf.append(messagePattern.substring(i, + messagePattern.length())); + return sbuf.toString(); + } + sbuf.append(messagePattern.substring(i, j)); + if (l == 0) { + sbuf.append(arg1); + } else { + sbuf.append(arg2); + } + i = j + 2; + } + } + // append the characters following the second {} pair. + sbuf.append(messagePattern.substring(i, messagePattern.length())); + return sbuf.toString(); + } +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java b/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java new file mode 100644 index 0000000..b15fbca --- /dev/null +++ b/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.helpers; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Level; + +/** + * An extension of the Level class that provides support for java.util.logging + * Levels. + * + * + * @author Scott Deboy ([email protected]) + */ + +public class UtilLoggingLevel extends Level { + + /** + * Serialization version id. + */ + private static final long serialVersionUID = 909301162611820211L; + + /** + * Numerical value for SEVERE. + */ + public static final int SEVERE_INT = 22000; + /** + * Numerical value for WARNING. + */ + public static final int WARNING_INT = 21000; + + //INFO level defined in parent as 20000..no need to redefine here + + /** + * Numerical value for CONFIG. + */ + public static final int CONFIG_INT = 14000; + /** + * Numerical value for FINE. + */ + public static final int FINE_INT = 13000; + /** + * Numerical value for FINER. + */ + public static final int FINER_INT = 12000; + /** + * Numerical value for FINEST. + */ + public static final int FINEST_INT = 11000; + /** + * Numerical value for UNKNOWN. + */ + public static final int UNKNOWN_INT = 10000; + + /** + * SEVERE. + */ + public static final UtilLoggingLevel SEVERE = + new UtilLoggingLevel(SEVERE_INT, "SEVERE", 0); + /** + * WARNING. + */ + public static final UtilLoggingLevel WARNING = + new UtilLoggingLevel(WARNING_INT, "WARNING", 4); + /** + * INFO. + */ + //note: we've aligned the int values of the java.util.logging INFO level with log4j's level + public static final UtilLoggingLevel INFO = + new UtilLoggingLevel(INFO_INT, "INFO", 5); + /** + * CONFIG. + */ + public static final UtilLoggingLevel CONFIG = + new UtilLoggingLevel(CONFIG_INT, "CONFIG", 6); + /** + * FINE. + */ + public static final UtilLoggingLevel FINE = + new UtilLoggingLevel(FINE_INT, "FINE", 7); + /** + * FINER. + */ + public static final UtilLoggingLevel FINER = + new UtilLoggingLevel(FINER_INT, "FINER", 8); + /** + * FINEST. + */ + public static final UtilLoggingLevel FINEST = + new UtilLoggingLevel(FINEST_INT, "FINEST", 9); + + /** + * Create new instance. + * @param level numeric value for level. + * @param levelStr symbolic name for level. + * @param syslogEquivalent Equivalent syslog severity. + */ + protected UtilLoggingLevel(final int level, + final String levelStr, + final int syslogEquivalent) { + super(level, levelStr, syslogEquivalent); + } + + /** + * Convert an integer passed as argument to a level. If the + * conversion fails, then this method returns the specified default. + * @param val numeric value. + * @param defaultLevel level to be returned if no level matches + * numeric value. + * @return matching level or default level. + */ + public static UtilLoggingLevel toLevel(final int val, + final UtilLoggingLevel defaultLevel) { + switch (val) { + case SEVERE_INT: + return SEVERE; + + case WARNING_INT: + return WARNING; + + case INFO_INT: + return INFO; + + case CONFIG_INT: + return CONFIG; + + case FINE_INT: + return FINE; + + case FINER_INT: + return FINER; + + case FINEST_INT: + return FINEST; + + default: + return defaultLevel; + } + } + + /** + * Gets level matching numeric value. + * @param val numeric value. + * @return matching level or UtilLoggerLevel.FINEST if no match. + */ + public static Level toLevel(final int val) { + return toLevel(val, FINEST); + } + + /** + * Gets list of supported levels. + * @return list of supported levels. + */ + public static List getAllPossibleLevels() { + ArrayList list = new ArrayList(); + list.add(FINE); + list.add(FINER); + list.add(FINEST); + list.add(INFO); + list.add(CONFIG); + list.add(WARNING); + list.add(SEVERE); + return list; + } + + /** + * Get level with specified symbolic name. + * @param s symbolic name. + * @return matching level or Level.DEBUG if no match. + */ + public static Level toLevel(final String s) { + return toLevel(s, Level.DEBUG); + } + + + /** + * Get level with specified symbolic name. + * @param sArg symbolic name. + * @param defaultLevel level to return if no match. + * @return matching level or defaultLevel if no match. + */ + public static Level toLevel(final String sArg, + final Level defaultLevel) { + if (sArg == null) { + return defaultLevel; + } + + String s = sArg.toUpperCase(); + + if (s.equals("SEVERE")) { + return SEVERE; + } + + //if(s.equals("FINE")) return Level.FINE; + if (s.equals("WARNING")) { + return WARNING; + } + + if (s.equals("INFO")) { + return INFO; + } + + if (s.equals("CONFI")) { + return CONFIG; + } + + if (s.equals("FINE")) { + return FINE; + } + + if (s.equals("FINER")) { + return FINER; + } + + if (s.equals("FINEST")) { + return FINEST; + } + return defaultLevel; + } + +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/AddressBased.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/net/AddressBased.java b/src/main/java/org/apache/log4j/net/AddressBased.java new file mode 100644 index 0000000..ccd2e6a --- /dev/null +++ b/src/main/java/org/apache/log4j/net/AddressBased.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.net; + + +/** + * Net based entities that 'work with' an Address + * should consider implementing this + * interface so that they can be treated generically. + * + * @author Paul Smith ([email protected]) + * + */ +public interface AddressBased extends NetworkBased { + /** + * Returns a String representation of the Address this instance + * encompasses. + * @return String representation of the Address + */ + String getAddress(); +} http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/JMSReceiver.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/log4j/net/JMSReceiver.java b/src/main/java/org/apache/log4j/net/JMSReceiver.java new file mode 100644 index 0000000..d22e25c --- /dev/null +++ b/src/main/java/org/apache/log4j/net/JMSReceiver.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.net; + +import java.io.FileInputStream; +import java.util.Properties; + +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TopicConnection; +import javax.jms.Topic; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicSubscriber; +import javax.jms.Session; +import javax.jms.TopicSession; +import javax.jms.ObjectMessage; + +import javax.naming.InitialContext; +import javax.naming.Context; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +import org.apache.log4j.spi.LoggingEvent; +import org.apache.log4j.plugins.Plugin; +import org.apache.log4j.plugins.Receiver; + +/** + JMSReceiver receives a remote logging event on a configured + JSM topic and "posts" it to a LoggerRepository as if the event was + generated locally. This class is designed to receive events from + the JMSAppender class (or classes that send compatible events). + + <p>Once the event has been "posted", it will be handled by the + appenders currently configured in the LoggerRespository. + + <p>This implementation borrows heavily from the JMSSink + implementation. + + @author Mark Womack + @author Paul Smith + @author Stephen Pain +*/ +public class JMSReceiver extends Receiver implements MessageListener { + + private boolean active = false; + + protected String topicFactoryName; + protected String topicName; + protected String userId; + protected String password; + protected TopicConnection topicConnection; + protected String jndiPath; + + private String remoteInfo; + private String providerUrl; + + public JMSReceiver() { } + + public JMSReceiver(String _topicFactoryName, String _topicName, + String _userId, String _password, String _jndiPath) { + topicFactoryName = _topicFactoryName; + topicName = _topicName; + userId = _userId; + password = _password; + jndiPath = _jndiPath; + } + + /** + * Sets the path to a properties file containing + * the initial context and jndi provider url + */ + public void setJndiPath(String _jndiPath) { + jndiPath = _jndiPath; + } + + /** + * Gets the path to a properties file containing + * the initial context and jndi provider url + */ + public String getJndiPath() { + return jndiPath; + } + + /** + Sets the JMS topic factory name to use when creating the + JMS connection. */ + public void setTopicFactoryName(String _topicFactoryName) { + topicFactoryName = _topicFactoryName; + } + + /** + Gets the curernt JMS topic factory name property. */ + public String getTopicFactoryName() { + return topicFactoryName; + } + + /** + * Sets the JMS topic name to use when creating the + * JMS connection. + */ + public void setTopicName(String _topicName) { + topicName = _topicName; + } + + /** + * Gets the curernt JMS topic name property. + */ + public String getTopicName() { + return topicName; + } + + /** + Sets the user id to use when creating the + JMS connection. */ + public void setUserId(String _userId) { + userId = _userId; + } + + /** + * Gets the current user id property. + */ + public String getUserId() { + return userId; + } + + /** + * Sets the password to use when creating the + * JMS connection. + */ + public void setPassword(String _password) { + password = _password; + } + + /** + * Gets the curernt password property. + */ + public String getPassword() { + return password; + } + + /** + * Returns true if the receiver is the same class and they are + * configured for the same properties, and super class also considers + * them to be equivalent. This is used by PluginRegistry when determining + * if the a similarly configured receiver is being started. + * + * @param testPlugin The plugin to test equivalency against. + * @return boolean True if the testPlugin is equivalent to this plugin. + */ + public boolean isEquivalent(Plugin testPlugin) { + // only do full check if an instance of this class + if (testPlugin instanceof JMSReceiver) { + + JMSReceiver receiver = (JMSReceiver)testPlugin; + + // check for same topic name and super class equivalency + return ( + topicFactoryName.equals(receiver.getTopicFactoryName()) && + (jndiPath == null || jndiPath.equals(receiver.getJndiPath())) && + super.isEquivalent(testPlugin) + ); + } + + return false; + } + + /** + Returns true if this receiver is active. */ + public synchronized boolean isActive() { + return active; + } + + /** + Sets the flag to indicate if receiver is active or not. */ + protected synchronized void setActive(boolean _active) { + active = _active; + } + + /** + Starts the JMSReceiver with the current options. */ + public void activateOptions() { + if (!isActive()) { + try { + remoteInfo = topicFactoryName + ":" + topicName; + + Context ctx = null; + if (jndiPath == null || jndiPath.equals("")) { + ctx = new InitialContext(); + } else { + FileInputStream is = new FileInputStream(jndiPath); + Properties p = new Properties(); + p.load(is); + is.close(); + ctx = new InitialContext(p); + } + + // give some more flexibility about the choice of a tab name + providerUrl = (String)ctx.getEnvironment().get(Context.PROVIDER_URL); + TopicConnectionFactory topicConnectionFactory; + topicConnectionFactory = + (TopicConnectionFactory) lookup(ctx, topicFactoryName); + + if (userId != null && password != null) { + topicConnection = + topicConnectionFactory.createTopicConnection(userId, password); + } else { + topicConnection = + topicConnectionFactory.createTopicConnection(); + } + + TopicSession topicSession = + topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + + Topic topic = (Topic)ctx.lookup(topicName); + + TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic); + + topicSubscriber.setMessageListener(this); + + topicConnection.start(); + + setActive(true); + } catch(Exception e) { + setActive(false); + if (topicConnection != null) { + try { + topicConnection.close(); + } catch (Exception e2) { + // do nothing + } + topicConnection = null; + } + getLogger().error("Could not start JMSReceiver.", e); + } + } + } + + /** + Called when the receiver should be stopped. */ + public synchronized void shutdown() { + if (isActive()) { + // mark this as no longer running + setActive(false); + + if (topicConnection != null) { + try { + topicConnection.close(); + } catch (Exception e) { + // do nothing + } + topicConnection = null; + } + } + } + + public void onMessage(Message message) { + try { + if(message instanceof ObjectMessage) { + // get the logging event and post it to the repository + ObjectMessage objectMessage = (ObjectMessage) message; + LoggingEvent event = (LoggingEvent) objectMessage.getObject(); + + // store the known remote info in an event property + event.setProperty("log4j.remoteSourceInfo", remoteInfo); + event.setProperty("log4j.jmsProviderUrl", providerUrl); + + doPost(event); + } else { + getLogger().warn("Received message is of type "+message.getJMSType() + +", was expecting ObjectMessage."); + } + } catch(Exception e) { + getLogger().error("Exception thrown while processing incoming message.", e); + } + } + + protected Object lookup(Context ctx, String name) throws NamingException { + try { + return ctx.lookup(name); + } catch(NameNotFoundException e) { + getLogger().error("Could not find name ["+name+"]."); + throw e; + } + } + +}
