1 5 package com.tc.object.bytecode.hook.impl; 6 7 import org.apache.commons.io.CopyUtils; 8 9 import com.tc.aspectwerkz.transform.InstrumentationContext; 10 import com.tc.aspectwerkz.transform.WeavingStrategy; 11 import com.tc.config.schema.L2ConfigForL1.L2Data; 12 import com.tc.config.schema.setup.ConfigurationSetupException; 13 import com.tc.config.schema.setup.FatalIllegalConfigurationChangeHandler; 14 import com.tc.config.schema.setup.L1TVSConfigurationSetupManager; 15 import com.tc.config.schema.setup.StandardTVSConfigurationSetupManagerFactory; 16 import com.tc.logging.TCLogger; 17 import com.tc.logging.TCLogging; 18 import com.tc.object.bytecode.Manageable; 19 import com.tc.object.bytecode.Manager; 20 import com.tc.object.bytecode.ManagerImpl; 21 import com.tc.object.bytecode.hook.ClassLoaderPreProcessorImpl; 22 import com.tc.object.bytecode.hook.DSOContext; 23 import com.tc.object.config.DSOClientConfigHelper; 24 import com.tc.object.config.IncompleteBootJarException; 25 import com.tc.object.config.StandardDSOClientConfigHelper; 26 import com.tc.object.config.UnverifiedBootJarException; 27 import com.tc.object.loaders.ClassProvider; 28 import com.tc.object.logging.InstrumentationLoggerImpl; 29 import com.tc.plugins.ModulesLoader; 30 import com.tc.util.Assert; 31 import com.tc.util.TCTimeoutException; 32 import com.terracottatech.config.ConfigurationModel; 33 34 import java.io.ByteArrayOutputStream ; 35 import java.io.IOException ; 36 import java.io.InputStream ; 37 import java.net.ConnectException ; 38 import java.net.MalformedURLException ; 39 import java.net.URL ; 40 import java.net.UnknownHostException ; 41 import java.util.Collection ; 42 import java.util.HashMap ; 43 44 public class DSOContextImpl implements DSOContext { 45 46 private static final TCLogger logger = TCLogging.getLogger(DSOContextImpl.class); 47 48 private static DSOClientConfigHelper staticConfigHelper; 49 private static PreparedComponentsFromL2Connection preparedComponentsFromL2Connection; 50 51 private final DSOClientConfigHelper configHelper; 52 private final Manager manager; 53 private final WeavingStrategy weavingStrategy; 54 55 59 public static DSOContext createGlobalContext(ClassProvider globalProvider) throws ConfigurationSetupException { 60 DSOClientConfigHelper configHelper = getGlobalConfigHelper(); 61 Manager manager = new ManagerImpl(configHelper, globalProvider, preparedComponentsFromL2Connection); 62 return new DSOContextImpl(configHelper, globalProvider, manager); 63 } 64 65 68 public static DSOContext createContext(DSOClientConfigHelper configHelper, ClassProvider classProvider, Manager manager) { 69 return new DSOContextImpl(configHelper, classProvider, manager); 70 } 71 72 public static boolean isDSOSessions(String appName) throws ConfigurationSetupException { 73 return getGlobalConfigHelper().isDSOSessions(appName); 74 } 75 76 private DSOContextImpl(DSOClientConfigHelper configHelper, ClassProvider classProvider, Manager manager) { 77 checkForProperlyInstrumentedBaseClasses(); 78 if (configHelper == null) { throw new NullPointerException (); } 79 80 this.configHelper = configHelper; 81 this.manager = manager; 82 weavingStrategy = new DefaultWeavingStrategy(configHelper, new InstrumentationLoggerImpl(configHelper 83 .instrumentationLoggingOptions())); 84 85 ModulesLoader.initModules(configHelper, classProvider, false); 86 validateBootJar(); 87 } 88 89 private void validateBootJar() { 90 try { 91 configHelper.verifyBootJarContents(); 92 } catch (final UnverifiedBootJarException ubjex) { 93 final StringBuffer msg = new StringBuffer (ubjex.getMessage() + " "); 94 msg.append("Unable to verify the contents of the boot jar; "); 95 msg.append("Please check the client logs for more information."); 96 logger.error(ubjex); 97 throw new RuntimeException (msg.toString()); 98 } catch (final IncompleteBootJarException ibjex) { 99 final StringBuffer msg = new StringBuffer (ibjex.getMessage() + " "); 100 msg.append("The DSO boot jar appears to be incomplete --- some pre-instrumented classes "); 101 msg.append("listed in your tc-config is not included in the boot jar file. This could "); 102 msg.append("happen if you've modified your DSO clients' tc-config file to specify additional "); 103 msg.append("classes for inclusion in the boot jar, but forgot to rebuild the boot jar. Or, you "); 104 msg.append("could be a using an older boot jar against a newer Terracotta client installation. "); 105 msg.append("Please check the client logs for the list of classes that were not found in your boot jar."); 106 logger.error(ibjex); 107 throw new RuntimeException (msg.toString()); 108 } 109 } 110 111 private void checkForProperlyInstrumentedBaseClasses() { 112 if (!Manageable.class.isAssignableFrom(HashMap .class)) { 113 StringBuffer msg = new StringBuffer (); 114 msg.append("The DSO boot jar is not prepended to your bootclasspath! "); 115 msg.append("Generate it using the make-boot-jar script "); 116 msg.append("and place the generated jar file in the bootclasspath "); 117 msg.append("(i.e. -Xbootclasspath/p:/path/to/terracotta/lib/dso-boot/dso-boot-xxx.jar)"); 118 throw new RuntimeException (msg.toString()); 119 } 120 } 121 122 public Manager getManager() { 123 return this.manager; 124 } 125 126 133 public byte[] preProcess(String name, byte[] data, int offset, int length, ClassLoader caller) { 134 InstrumentationContext context = new InstrumentationContext(name, data, caller); 135 weavingStrategy.transform(name, context); 136 return context.getCurrentBytecode(); 137 } 138 139 public void postProcess(Class clazz, ClassLoader caller) { 140 } 142 143 public void addTransient(String className, String fieldName) { 145 this.configHelper.addTransient(className, fieldName); 146 } 147 148 public void addInclude(String expression, boolean callConstructorOnLoad, String lockExpression) { 150 this.configHelper.addIncludeAndLockIfRequired(expression, true, callConstructorOnLoad, false, lockExpression); 151 } 152 153 public Collection getDSOSpringConfigHelpers() { 155 return this.configHelper.getDSOSpringConfigs(); 156 } 157 158 private synchronized static DSOClientConfigHelper getGlobalConfigHelper() throws ConfigurationSetupException { 159 if (staticConfigHelper == null) { 160 StandardTVSConfigurationSetupManagerFactory factory = new StandardTVSConfigurationSetupManagerFactory( 161 false, 162 new FatalIllegalConfigurationChangeHandler()); 163 164 logger.debug("Created StandardTVSConfigurationSetupManagerFactory."); 165 L1TVSConfigurationSetupManager config = factory.createL1TVSConfigurationSetupManager(); 166 config.setupLogging(); 167 logger.debug("Created L1TVSConfigurationSetupManager."); 168 169 try { 170 preparedComponentsFromL2Connection = validateMakeL2Connection(config); 171 } catch (Exception e) { 172 throw new ConfigurationSetupException(e.getLocalizedMessage(), e); 173 } 174 staticConfigHelper = new StandardDSOClientConfigHelper(config); 175 } 176 177 return staticConfigHelper; 178 } 179 180 private static PreparedComponentsFromL2Connection validateMakeL2Connection(L1TVSConfigurationSetupManager config) 181 throws UnknownHostException , IOException , TCTimeoutException { 182 L2Data[] l2Data = (L2Data[]) config.l2Config().l2Data().getObjects(); 183 Assert.assertNotNull(l2Data); 184 185 String serverHost = l2Data[0].host(); 186 187 if (false && !config.loadedFromTrustedSource()) { 188 String serverConfigMode = getServerConfigMode(serverHost, l2Data[0].dsoPort()); 189 190 if (serverConfigMode != null && serverConfigMode.equals(ConfigurationModel.PRODUCTION)) { 191 String text = "Configuration constraint violation: " 192 + "untrusted client configuration not allowed against production server"; 193 throw new AssertionError (text); 194 } 195 } 196 197 return new PreparedComponentsFromL2Connection(config); 198 } 199 200 private static final long MAX_HTTP_FETCH_TIME = 30 * 1000; private static final long HTTP_FETCH_RETRY_INTERVAL = 1 * 1000; 203 private static String getServerConfigMode(String serverHost, int httpPort) throws MalformedURLException , 204 TCTimeoutException, IOException { 205 URL theURL = new URL ("http", serverHost, httpPort, "/config?query=mode"); 206 long startTime = System.currentTimeMillis(); 207 long lastTrial = 0; 208 209 while (System.currentTimeMillis() < (startTime + MAX_HTTP_FETCH_TIME)) { 210 try { 211 long untilNextTrial = HTTP_FETCH_RETRY_INTERVAL - (System.currentTimeMillis() - lastTrial); 212 213 if (untilNextTrial > 0) { 214 try { 215 Thread.sleep(untilNextTrial); 216 } catch (InterruptedException ie) { 217 } 219 } 220 221 logger.debug("Opening connection to: " + theURL + " to fetch server configuration."); 222 223 lastTrial = System.currentTimeMillis(); 224 InputStream in = theURL.openStream(); 225 logger.debug("Got input stream to: " + theURL); 226 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 227 228 CopyUtils.copy(in, baos); 229 230 return baos.toString(); 231 } catch (ConnectException ce) { 232 logger.warn("Unable to fetch configuration mode from L2 at '" + theURL + "'; trying again. " 233 + "(Is an L2 running at that address?): " + ce.getLocalizedMessage()); 234 } 236 } 237 238 throw new TCTimeoutException("We tried for " + (int) ((System.currentTimeMillis() - startTime) / 1000) 239 + " seconds, but couldn't fetch system configuration mode from the L2 " + "at '" 240 + theURL + "'. Is the L2 running?"); 241 } 242 243 public int getSessionLockType(String appName) { 244 return configHelper.getSessionLockType(appName); 245 } 246 } 247 | Popular Tags |