/** * Copyright (C) 2000-2016 Atomikos <info@atomikos.com> * * LICENSE CONDITIONS * * See http://www.atomikos.com/Main/WhichLicenseApplies for details. */ package com.atomikos.icatch.provider.imp; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Map.Entry; import java.util.Properties; import java.util.ServiceLoader; import com.atomikos.icatch.CompositeTransactionManager; import com.atomikos.icatch.SysException; import com.atomikos.icatch.TransactionServicePlugin; import com.atomikos.icatch.config.Configuration; import com.atomikos.icatch.imp.CompositeTransactionManagerImp; import com.atomikos.icatch.imp.TransactionServiceImp; import com.atomikos.icatch.provider.Assembler; import com.atomikos.icatch.provider.ConfigProperties; import com.atomikos.icatch.provider.TransactionServiceProvider; import com.atomikos.logging.LoggerFactory; import com.atomikos.persistence.imp.StateRecoveryManagerImp; import com.atomikos.recovery.LogException; import com.atomikos.recovery.OltpLogFactory; import com.atomikos.recovery.Repository; import com.atomikos.recovery.OltpLog; import com.atomikos.recovery.RecoveryLog; import com.atomikos.recovery.imp.CachedRepository; import com.atomikos.recovery.imp.FileSystemRepository; import com.atomikos.recovery.imp.InMemoryRepository; import com.atomikos.recovery.imp.OltpLogImp; import com.atomikos.recovery.imp.RecoveryLogImp; import com.atomikos.util.Atomikos; import com.atomikos.util.ClassLoadingHelper; import com.atomikos.util.UniqueIdMgr; public class AssemblerImp implements Assembler { private static final String DEFAULT_PROPERTIES_FILE_NAME = "transactions-defaults.properties"; private static final String JTA_PROPERTIES_FILE_NAME = "jta.properties"; private static final String TRANSACTIONS_PROPERTIES_FILE_NAME = "transactions.properties"; private static final int MAX_TID_LENGTH = 64; //XID limitation private static com.atomikos.logging.Logger LOGGER = LoggerFactory.createLogger(AssemblerImp.class); private void loadPropertiesFromClasspath(Properties p, String fileName){ URL url = null; //first look in application classpath (cf ISSUE 10091) url = ClassLoadingHelper.loadResourceFromClasspath(getClass(), fileName); if (url == null) { url = getClass().getClassLoader().getSystemResource ( fileName ); } if (url != null) { loadPropertiesFromUrl(p, url); } else { LOGGER.logTrace("Could not find expected property file: " + fileName); } } private void loadPropertiesFromUrl(Properties p, URL url) { InputStream in; try { in = url.openStream(); p.load(in); in.close(); LOGGER.logInfo("Loaded " + url.toString()); } catch (IOException e) { LOGGER.logTrace("Failed to load property file: " + url.toString(), e); } } /** * Called by ServiceLoader. */ public AssemblerImp() { } @Override public ConfigProperties initializeProperties() { Properties defaults = new Properties(); loadPropertiesFromClasspath(defaults, DEFAULT_PROPERTIES_FILE_NAME); Properties transactionsProperties = new Properties(defaults); loadPropertiesFromClasspath(transactionsProperties, TRANSACTIONS_PROPERTIES_FILE_NAME); Properties jtaProperties = new Properties(transactionsProperties); loadPropertiesFromClasspath(jtaProperties, JTA_PROPERTIES_FILE_NAME); Properties customProperties = new Properties(jtaProperties); loadPropertiesFromCustomFilePath(customProperties); Properties finalProperties = new Properties(customProperties); ConfigProperties configProperties = new ConfigProperties(finalProperties); checkRegistration(configProperties); return configProperties; } private void checkRegistration(ConfigProperties configProperties) { if (configProperties.getCompletedProperties().getProperty("com.atomikos.icatch.registered") == null) { String message ="Thanks for using Atomikos! Evaluate http://www.atomikos.com/Main/ExtremeTransactions for advanced features and professional support\n" + "or register at http://www.atomikos.com/Main/RegisterYourDownload to disable this message and receive FREE tips & advice"; LOGGER.logWarning(message); System.out.println(message); } if (Atomikos.isEvaluationVersion()) { String message ="This product (ExtremeTransactions) is licensed for DEVELOPMENT ONLY - for production use you need to purchase a subscription via https://www.atomikos.com/Main/BuyOnline"; LOGGER.logWarning(message); System.err.println(message); } } private void loadPropertiesFromCustomFilePath(Properties customProperties) { String customFilePath = System.getProperty(ConfigProperties.FILE_PATH_PROPERTY_NAME); if (customFilePath != null) { File file = new File(customFilePath); URL url; try { url = file.toURL(); loadPropertiesFromUrl(customProperties, url); } catch (MalformedURLException e) { LOGGER.logFatal("File not found: " + customFilePath); } } } private void logProperties(Properties properties) { for (Entry<Object, Object> entry : properties.entrySet()) { LOGGER.logInfo("USING: " + entry.getKey() + " = " + entry.getValue()); } } @Override public TransactionServiceProvider assembleTransactionService( ConfigProperties configProperties) { RecoveryLog recoveryLog =null; logProperties(configProperties.getCompletedProperties()); String tmUniqueName = configProperties.getTmUniqueName(); long maxTimeout = configProperties.getMaxTimeout(); int maxActives = configProperties.getMaxActives(); boolean threaded2pc = configProperties.getThreaded2pc(); OltpLog oltpLog = createOltpLogFromClasspath(); if (oltpLog == null) { LOGGER.logInfo("Using default (local) logging and recovery..."); Repository repository = createRepository(configProperties); oltpLog = createOltpLog(repository); //??? Assemble recoveryLog recoveryLog = createRecoveryLog(repository); } StateRecoveryManagerImp recoveryManager = new StateRecoveryManagerImp(); recoveryManager.setOltpLog(oltpLog); UniqueIdMgr idMgr = new UniqueIdMgr ( tmUniqueName ); int overflow = idMgr.getMaxIdLengthInBytes() - MAX_TID_LENGTH; if ( overflow > 0 ) { // see case 73086 String msg = "Value too long : " + tmUniqueName; LOGGER.logFatal ( msg ); throw new SysException(msg); } return new TransactionServiceImp(tmUniqueName, recoveryManager, idMgr, maxTimeout, maxActives, !threaded2pc, recoveryLog); } private Repository createRepository(ConfigProperties configProperties) { boolean enableLogging = configProperties.getEnableLogging(); Repository repository; if (enableLogging) { try { repository = createCoordinatorLogEntryRepository(configProperties); } catch ( LogException le ) { throw new SysException ( "Error in init: " + le.getMessage (), le ); } } else { repository = createInMemoryCoordinatorLogEntryRepository(configProperties); } return repository; } private OltpLog createOltpLogFromClasspath() { OltpLog ret = null; ServiceLoader<OltpLogFactory> loader = ServiceLoader.load(OltpLogFactory.class,Configuration.class.getClassLoader()); int i = 0; for (OltpLogFactory l : loader ) { ret = l.createOltpLog(); i++; } if (i > 1) { String msg = "More than one OltpLogFactory found in classpath - error in configuration!"; LOGGER.logFatal(msg); throw new SysException(msg); } return ret; } private Repository createInMemoryCoordinatorLogEntryRepository( ConfigProperties configProperties) { InMemoryRepository inMemoryCoordinatorLogEntryRepository = new InMemoryRepository(); inMemoryCoordinatorLogEntryRepository.init(); return inMemoryCoordinatorLogEntryRepository; } private RecoveryLog createRecoveryLog(Repository repository) { RecoveryLogImp recoveryLog = new RecoveryLogImp(); recoveryLog.setRepository(repository); return recoveryLog; } private OltpLog createOltpLog(Repository repository) { OltpLogImp oltpLog = new OltpLogImp(); oltpLog.setRepository(repository); return oltpLog; } private CachedRepository createCoordinatorLogEntryRepository( ConfigProperties configProperties) throws LogException { InMemoryRepository inMemoryCoordinatorLogEntryRepository = new InMemoryRepository(); inMemoryCoordinatorLogEntryRepository.init(); FileSystemRepository backupCoordinatorLogEntryRepository = new FileSystemRepository(); backupCoordinatorLogEntryRepository.init(); CachedRepository repository = new CachedRepository(inMemoryCoordinatorLogEntryRepository, backupCoordinatorLogEntryRepository); repository.init(); return repository; } @Override public CompositeTransactionManager assembleCompositeTransactionManager() { return new CompositeTransactionManagerImp(); } }