/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed 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.pentaho.di.core.logging; import java.util.ArrayList; import java.util.List; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.variables.VariableSpace; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.repository.RepositoryAttributeInterface; import org.pentaho.di.trans.HasDatabasesInterface; import org.w3c.dom.Node; public abstract class BaseLogTable { public static final String XML_TAG = "field"; public static String PROP_LOG_TABLE_CONNECTION_NAME = "_LOG_TABLE_CONNECTION_NAME"; public static String PROP_LOG_TABLE_SCHEMA_NAME = "_LOG_TABLE_SCHEMA_NAME"; public static String PROP_LOG_TABLE_TABLE_NAME = "_LOG_TABLE_TABLE_NAME"; public static String PROP_LOG_TABLE_FIELD_ID = "_LOG_TABLE_FIELD_ID"; public static String PROP_LOG_TABLE_FIELD_NAME = "_LOG_TABLE_FIELD_NAME"; public static String PROP_LOG_TABLE_FIELD_ENABLED = "_LOG_TABLE_FIELD_ENABLED"; public static String PROP_LOG_TABLE_FIELD_SUBJECT = "_LOG_TABLE_FIELD_SUBJECT"; public static String PROP_LOG_TABLE_INTERVAL = "LOG_TABLE_INTERVAL"; public static String PROP_LOG_TABLE_SIZE_LIMIT = "LOG_TABLE_SIZE_LIMIT"; public static String PROP_LOG_TABLE_TIMEOUT_DAYS = "_LOG_TABLE_TIMEOUT_IN_DAYS"; protected VariableSpace space; protected HasDatabasesInterface databasesInterface; protected String connectionName; protected String schemaName; protected String tableName; protected String timeoutInDays; protected List<LogTableField> fields; public BaseLogTable( VariableSpace space, HasDatabasesInterface databasesInterface, String connectionName, String schemaName, String tableName ) { this.space = space; this.databasesInterface = databasesInterface; this.connectionName = connectionName; this.schemaName = schemaName; this.tableName = tableName; this.fields = new ArrayList<LogTableField>(); } public void replaceMeta( BaseLogTable baseLogTable ) { this.space = baseLogTable.space; this.databasesInterface = baseLogTable.databasesInterface; this.connectionName = baseLogTable.connectionName; this.schemaName = baseLogTable.schemaName; this.tableName = baseLogTable.tableName; this.timeoutInDays = baseLogTable.timeoutInDays; fields.clear(); for ( LogTableField field : baseLogTable.fields ) { try { fields.add( (LogTableField) field.clone() ); } catch ( CloneNotSupportedException e ) { throw new RuntimeException( "Clone problem with the base log table", e ); } } } public String toString() { if ( isDefined() ) { return getDatabaseMeta().getName() + "-" + getActualTableName(); } return super.toString(); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } /** * Save this core information of the log table to the repository using the specified attribute interface. * * @param attributeInterface * The attribute interface to use to set attributes * @throws KettleException */ public void saveToRepository( RepositoryAttributeInterface attributeInterface ) throws KettleException { attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_CONNECTION_NAME, getConnectionName() ); attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_SCHEMA_NAME, getSchemaName() ); attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_TABLE_NAME, getTableName() ); attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_TIMEOUT_DAYS, getTimeoutInDays() ); // Store the fields too... // for ( int i = 0; i < getFields().size(); i++ ) { LogTableField field = getFields().get( i ); attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_FIELD_ID + i, field.getId() ); attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_FIELD_NAME + i, field.getFieldName() ); attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_FIELD_ENABLED + i, field.isEnabled() ); if ( field.isSubjectAllowed() ) { attributeInterface.setAttribute( getLogTableCode() + PROP_LOG_TABLE_FIELD_SUBJECT + i, field.getSubject() == null ? null : field .getSubject().toString() ); } } } public void loadFromRepository( RepositoryAttributeInterface attributeInterface ) throws KettleException { String connectionNameFromRepository = attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_CONNECTION_NAME ); if ( connectionNameFromRepository != null ) { connectionName = connectionNameFromRepository; } String schemaNameFromRepository = attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_SCHEMA_NAME ); if ( schemaNameFromRepository != null ) { schemaName = schemaNameFromRepository; } String tableNameFromRepository = attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_TABLE_NAME ); if ( tableNameFromRepository != null ) { tableName = tableNameFromRepository; } timeoutInDays = attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_TIMEOUT_DAYS ); for ( int i = 0; i < getFields().size(); i++ ) { String id = attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_FIELD_ID + i ); // Only read further if the ID is available. // For backward compatibility, this might not be provided yet! // if ( id != null ) { LogTableField field = findField( id ); if ( field != null ) { field.setFieldName( attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_FIELD_NAME + i ) ); field.setEnabled( attributeInterface.getAttributeBoolean( getLogTableCode() + PROP_LOG_TABLE_FIELD_ENABLED + i ) ); if ( field.isSubjectAllowed() ) { field.setSubject( attributeInterface.getAttributeString( getLogTableCode() + PROP_LOG_TABLE_FIELD_SUBJECT + i ) ); } } } } } public abstract String getLogTableCode(); public abstract String getConnectionNameVariable(); public abstract String getSchemaNameVariable(); public abstract String getTableNameVariable(); /** * @return the databaseMeta */ public DatabaseMeta getDatabaseMeta() { String name = getActualConnectionName(); if ( name == null ) { return null; } if ( databasesInterface == null ) { return null; } return databasesInterface.findDatabase( name ); } /** * @return the connectionName */ public String getActualConnectionName() { String name = space.environmentSubstitute( connectionName ); if ( Utils.isEmpty( name ) ) { name = space.getVariable( getConnectionNameVariable() ); } if ( Utils.isEmpty( name ) ) { return null; } else { return name; } } /** * @return the schemaName */ public String getActualSchemaName() { if ( !Utils.isEmpty( schemaName ) ) { return space.environmentSubstitute( schemaName ); } String name = space.getVariable( getSchemaNameVariable() ); if ( Utils.isEmpty( name ) ) { return null; } else { return name; } } /** * @param schemaName * the schemaName to set */ public void setSchemaName( String schemaName ) { this.schemaName = schemaName; } public String getSchemaName() { return schemaName; } /** * @return the tableName */ public String getActualTableName() { if ( !Utils.isEmpty( tableName ) ) { return space.environmentSubstitute( tableName ); } String name = space.getVariable( getTableNameVariable() ); if ( Utils.isEmpty( name ) ) { return null; } else { return name; } } public String getTableName() { return tableName; } /** * @param tableName * the tableName to set */ public void setTableName( String tableName ) { this.tableName = tableName; } public String getQuotedSchemaTableCombination() { return getDatabaseMeta().getQuotedSchemaTableCombination( getActualSchemaName(), getActualTableName() ); } /** * @return the fields */ public List<LogTableField> getFields() { return fields; } /** * @param fields * the fields to set */ public void setFields( List<LogTableField> fields ) { this.fields = fields; } /** * Find a log table field in this log table definition. Use the id of the field to do the lookup. * * @param id * the id of the field to search for * @return the log table field or null if nothing was found. */ public LogTableField findField( String id ) { for ( LogTableField field : fields ) { if ( field.getId().equals( id ) ) { return field; } } return null; } /** * Get the subject of a field with the specified ID * * @param id * @return the subject or null if no field could be find with the specified id */ public Object getSubject( String id ) { LogTableField field = findField( id ); if ( field == null ) { return null; } return field.getSubject(); } /** * Return the subject in the form of a string for the specified ID. * * @param id * the id of the field to look for. * @return the string of the subject (name of step) or null if nothing was found. */ public String getSubjectString( String id ) { LogTableField field = findField( id ); if ( field == null ) { return null; } if ( field.getSubject() == null ) { return null; } return field.getSubject().toString(); } public boolean containsKeyField() { for ( LogTableField field : fields ) { if ( field.isKey() ) { return true; } } return false; } /** * @return the field that represents the log date field or null if none was defined. */ public LogTableField getLogDateField() { for ( LogTableField field : fields ) { if ( field.isLogDateField() ) { return field; } } return null; } /** * @return the field that represents the key to this logging table (batch id etc) */ public LogTableField getKeyField() { for ( LogTableField field : fields ) { if ( field.isKey() ) { return field; } } return null; } /** * @return the field that represents the logging text (or null if none is found) */ public LogTableField getLogField() { for ( LogTableField field : fields ) { if ( field.isLogField() ) { return field; } } return null; } /** * @return the field that represents the status (or null if none is found) */ public LogTableField getStatusField() { for ( LogTableField field : fields ) { if ( field.isStatusField() ) { return field; } } return null; } /** * @return the field that represents the number of errors (or null if none is found) */ public LogTableField getErrorsField() { for ( LogTableField field : fields ) { if ( field.isErrorsField() ) { return field; } } return null; } /** * @return the field that represents the name of the object that is being used (or null if none is found) */ public LogTableField getNameField() { for ( LogTableField field : fields ) { if ( field.isNameField() ) { return field; } } return null; } protected String getFieldsXML() { StringBuilder retval = new StringBuilder(); for ( LogTableField field : fields ) { retval.append( " " ).append( XMLHandler.openTag( XML_TAG ) ).append( Const.CR ); retval.append( " " ).append( XMLHandler.addTagValue( "id", field.getId() ) ); retval.append( " " ).append( XMLHandler.addTagValue( "enabled", field.isEnabled() ) ); retval.append( " " ).append( XMLHandler.addTagValue( "name", field.getFieldName() ) ); if ( field.isSubjectAllowed() ) { retval.append( " " ).append( XMLHandler.addTagValue( "subject", field.getSubject() == null ? null : field.getSubject().toString() ) ); } retval.append( " " ).append( XMLHandler.closeTag( XML_TAG ) ).append( Const.CR ); } return retval.toString(); } public void loadFieldsXML( Node node ) { int nr = XMLHandler.countNodes( node, BaseLogTable.XML_TAG ); for ( int i = 0; i < nr; i++ ) { Node fieldNode = XMLHandler.getSubNodeByNr( node, BaseLogTable.XML_TAG, i ); String id = XMLHandler.getTagValue( fieldNode, "id" ); LogTableField field = findField( id ); if ( field == null && i < fields.size() ) { field = fields.get( i ); // backward compatible until we go GA } if ( field != null ) { field.setFieldName( XMLHandler.getTagValue( fieldNode, "name" ) ); field.setEnabled( "Y".equalsIgnoreCase( XMLHandler.getTagValue( fieldNode, "enabled" ) ) ); } } } public boolean isDefined() { return getDatabaseMeta() != null && !Utils.isEmpty( getActualTableName() ); } /** * @return the timeoutInDays */ public String getTimeoutInDays() { return timeoutInDays; } /** * @param timeoutInDays * the timeoutInDays to set */ public void setTimeoutInDays( String timeoutInDays ) { this.timeoutInDays = timeoutInDays; } /** * @return the connectionName */ public String getConnectionName() { return connectionName; } /** * @param connectionName * the connectionName to set */ public void setConnectionName( String connectionName ) { this.connectionName = connectionName; } protected String getLogBuffer( VariableSpace space, String logChannelId, LogStatus status, String limit ) { StringBuffer buffer = KettleLogStore.getAppender().getBuffer( logChannelId, true ); if ( Utils.isEmpty( limit ) ) { String defaultLimit = space.getVariable( Const.KETTLE_LOG_SIZE_LIMIT, null ); if ( !Utils.isEmpty( defaultLimit ) ) { limit = defaultLimit; } } // See if we need to limit the amount of rows // int nrLines = Utils.isEmpty( limit ) ? -1 : Const.toInt( space.environmentSubstitute( limit ), -1 ); if ( nrLines > 0 ) { int start = buffer.length() - 1; for ( int i = 0; i < nrLines && start > 0; i++ ) { start = buffer.lastIndexOf( Const.CR, start - 1 ); } if ( start > 0 ) { buffer.delete( 0, start + Const.CR.length() ); } } return buffer.append( Const.CR + status.getStatus().toUpperCase() + Const.CR ).toString(); } // PDI-7070: implement equals for comparison of job/trans log table to its parent log table @Override public boolean equals( Object obj ) { if ( obj == null || !( obj instanceof BaseLogTable ) ) { return false; } BaseLogTable blt = (BaseLogTable) obj; // Get actual names for comparison String cName = this.getActualConnectionName(); String sName = this.getActualSchemaName(); String tName = this.getActualTableName(); return ( ( cName == null ? blt.getActualConnectionName() == null : cName .equals( blt.getActualConnectionName() ) ) && ( sName == null ? blt.getActualSchemaName() == null : sName.equals( blt.getActualSchemaName() ) ) && ( tName == null ? blt.getActualTableName() == null : tName.equals( blt.getActualTableName() ) ) ); } public void setAllGlobalParametersToNull() { boolean clearGlobalVariables = Boolean.valueOf( System.getProperties().getProperty( Const.KETTLE_GLOBAL_LOG_VARIABLES_CLEAR_ON_EXPORT, "false" ) ); if ( clearGlobalVariables ) { schemaName = isGlobalParameter( schemaName ) ? null : schemaName; connectionName = isGlobalParameter( connectionName ) ? null : connectionName; tableName = isGlobalParameter( tableName ) ? null : tableName; timeoutInDays = isGlobalParameter( timeoutInDays ) ? null : timeoutInDays; } } protected boolean isGlobalParameter( String parameter ) { if ( parameter == null ) { return false; } if ( parameter.startsWith( "${" ) && parameter.endsWith( "}" ) ) { return System.getProperty( parameter.substring( 2, parameter.length() - 1 ) ) != null; } return false; } }