/* * $Id: RelayFactory.java 272015 2011-05-21 03:03:57Z cbotev $ */ package com.linkedin.databus2.relay; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * 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. * */ import java.lang.management.ManagementFactory; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.management.MBeanServer; import javax.sql.DataSource; import org.apache.log4j.Logger; import com.linkedin.databus.core.DbusEventBufferAppendable; import com.linkedin.databus.core.UnsupportedKeyException; import com.linkedin.databus.core.monitoring.mbean.DbusEventsStatisticsCollector; import com.linkedin.databus.core.util.InvalidConfigException; import com.linkedin.databus.monitoring.mbean.EventSourceStatistics; import com.linkedin.databus2.core.DatabusException; import com.linkedin.databus2.core.seq.MaxSCNReaderWriter; import com.linkedin.databus2.producers.ConstantPartitionFunction; import com.linkedin.databus2.producers.EventCreationException; import com.linkedin.databus2.producers.EventProducer; import com.linkedin.databus2.producers.PartitionFunction; import com.linkedin.databus2.producers.db.EventFactory; import com.linkedin.databus2.producers.db.OracleTriggerMonitoredSourceInfo; import com.linkedin.databus2.producers.db.OracleAvroGenericEventFactory; import com.linkedin.databus2.producers.db.OracleEventProducer; import com.linkedin.databus2.relay.config.LogicalSourceStaticConfig; import com.linkedin.databus2.relay.config.PhysicalSourceStaticConfig; import com.linkedin.databus2.schemas.NoSuchSchemaException; import com.linkedin.databus2.schemas.SchemaRegistryService; /** * @author Jemiah Westerman<jwesterman@linkedin.com> * @version $Revision: 272015 $ */ public class OracleEventProducerFactory { private final Logger _log = Logger.getLogger(getClass()); public EventProducer buildEventProducer(PhysicalSourceStaticConfig physicalSourceConfig, SchemaRegistryService schemaRegistryService, DbusEventBufferAppendable dbusEventBuffer, MBeanServer mbeanServer, DbusEventsStatisticsCollector dbusEventsStatisticsCollector, MaxSCNReaderWriter _maxScnReaderWriter ) throws DatabusException, EventCreationException, UnsupportedKeyException, SQLException, InvalidConfigException { // Make sure the URI from the configuration file identifies an Oracle JDBC source. String uri = physicalSourceConfig.getUri(); if(!uri.startsWith("jdbc:oracle")) { throw new InvalidConfigException("Invalid source URI (" + physicalSourceConfig.getUri() + "). Only jdbc:oracle: URIs are supported."); } // Parse each one of the logical sources List<OracleTriggerMonitoredSourceInfo> sources = new ArrayList<OracleTriggerMonitoredSourceInfo>(); for(LogicalSourceStaticConfig sourceConfig : physicalSourceConfig.getSources()) { OracleTriggerMonitoredSourceInfo source = buildOracleMonitoredSourceInfo(sourceConfig, physicalSourceConfig, schemaRegistryService); sources.add(source); } DataSource ds = null; try { ds = OracleJarUtils.createOracleDataSource(uri); } catch (Exception e) { String errMsg = "Oracle URI likely not supported. Trouble creating OracleDataSource"; _log.error(errMsg); throw new InvalidConfigException(errMsg + e.getMessage()); } // Create the event producer EventProducer eventProducer = new OracleEventProducer(sources, ds, dbusEventBuffer, true, dbusEventsStatisticsCollector, _maxScnReaderWriter, physicalSourceConfig, ManagementFactory.getPlatformMBeanServer()); _log.info("Created OracleEventProducer for config: " + physicalSourceConfig + " with slowSourceQueryThreshold = " + physicalSourceConfig.getSlowSourceQueryThreshold()); return eventProducer; } protected OracleAvroGenericEventFactory createEventFactory( String eventViewSchema, String eventView, LogicalSourceStaticConfig sourceConfig, PhysicalSourceStaticConfig pConfig, String eventSchema, PartitionFunction partitionFunction) throws EventCreationException, UnsupportedKeyException { return new OracleAvroGenericEventFactory(sourceConfig.getId(), (short)pConfig.getId(), eventSchema, partitionFunction,pConfig.getReplBitSetter()); } public OracleTriggerMonitoredSourceInfo buildOracleMonitoredSourceInfo( LogicalSourceStaticConfig sourceConfig, PhysicalSourceStaticConfig pConfig, SchemaRegistryService schemaRegistryService) throws DatabusException, EventCreationException, UnsupportedKeyException, InvalidConfigException { String schema = null; try { schema = schemaRegistryService.fetchLatestSchemaBySourceName(sourceConfig.getName()); } catch (NoSuchSchemaException e) { throw new InvalidConfigException("Unable to load the schema for source (" + sourceConfig.getName() + ")."); } if(schema == null) { throw new InvalidConfigException("Unable to load the schema for source (" + sourceConfig.getName() + ")."); } _log.info("Loading schema for source id " + sourceConfig.getId() + ": " + schema); String eventViewSchema; String eventView; if(sourceConfig.getUri().indexOf('.') != -1) { String[] parts = sourceConfig.getUri().split("\\."); eventViewSchema = parts[0]; eventView = parts[1]; } else { eventViewSchema = null; eventView = sourceConfig.getUri(); } if(eventView.toLowerCase().startsWith("sy$")) { eventView = eventView.substring(3); } PartitionFunction partitionFunction = buildPartitionFunction(sourceConfig); EventFactory factory = createEventFactory(eventViewSchema, eventView, sourceConfig, pConfig, schema, partitionFunction); EventSourceStatistics statisticsBean = new EventSourceStatistics(sourceConfig.getName()); OracleTriggerMonitoredSourceInfo sourceInfo = new OracleTriggerMonitoredSourceInfo(sourceConfig.getId(), sourceConfig.getName(), eventViewSchema, eventView, factory, statisticsBean, sourceConfig.getRegularQueryHints(), sourceConfig.getChunkedTxnQueryHints(), sourceConfig.getChunkedScnQueryHints(), sourceConfig.isSkipInfinityScn()); return sourceInfo; } public PartitionFunction buildPartitionFunction(LogicalSourceStaticConfig sourceConfig) throws InvalidConfigException { String partitionFunction = sourceConfig.getPartitionFunction(); if(partitionFunction.startsWith("constant:")) { try { String numberPart = partitionFunction.substring("constant:".length()).trim(); short constantPartitionNumber = Short.valueOf(numberPart); return new ConstantPartitionFunction(constantPartitionNumber); } catch(Exception ex) { // Could be a NumberFormatException, IndexOutOfBoundsException or other exception when trying to parse the partition number. throw new InvalidConfigException("Invalid partition configuration (" + partitionFunction + "). " + "Could not parse the constant partition number."); } } else { throw new InvalidConfigException("Invalid partition configuration (" + partitionFunction + ")."); } } }