diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d6d6b20 --- /dev/null +++ b/pom.xml @@ -0,0 +1,131 @@ + + 4.0.0 + com.tomecode.oracle.osb12c + osb12c-xquery-warmup + 0.0.1-SNAPSHOT + + + + c:/Oracle/FMW12c1221/wlserver + c:/Oracle/FMW12c1221/osb + c:/Oracle/FMW12c1221/oracle_common + + + + + com.oracle.weblogic + weblogic + 12c + system + ${wls12cHome}/server/lib/weblogic.jar + + + com.oracle.osb + oracle.servicebus.configfwk + 12c + system + ${osb12cHome}/lib/modules/oracle.servicebus.configfwk.jar + + + com.oracle.osb + oracle.servicebus.resources.xquery + 12c + system + ${osb12cHome}/lib/modules/oracle.servicebus.resources.xquery.jar + + + com.oracle.osb + oracle.servicebus.services.core + 12c + system + ${osb12cHome}/lib/modules/oracle.servicebus.services.core.jar + + + com.oracle.osb + oracle.servicebus.resources.core + 12c + system + ${osb12cHome}/lib/modules/oracle.servicebus.resources.core.jar + + + com.oracle.osb + oracle.servicebus.kernel-api + 12c + system + ${osb12cHome}/lib/modules/oracle.servicebus.kernel-api.jar + + + com.oracle.common + xqjapi + 12c + system + ${common12cHome}/modules/oracle.xdk/xqjapi.jar + + + com.oracle.common + xqjapi + 12c + system + ${common12cHome}/modules/oracle.xdk/xqjapi.jar + + + com.oracle.common + com.bea.core.xquery + 12c + system + ${common12cHome}/modules/com.bea.core.xquery_1.8.0.0.jar + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.0.0 + + + ear + package + + single + + + false + + ${basedir}/src/main/ear/META-INF/application.xml + + + + true + true + + + 1.0 + ${project.version}-${maven.build.timestamp} + APP-INF/lib/${project.artifactId}.jar + + + + ${basedir}/src/main/assembly/ear.xml + + ${project.artifactId} + + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..77c2174 --- /dev/null +++ b/readme.md @@ -0,0 +1,23 @@ +# osb12c-xquery-warmup +Recompile/warm-up any XQueries at runtime in the OSB 12c + +# What is it + - a simple application (packaged as EAR) deployed in OSB/WLS + - activated when the OSB starting or XQuery is/was deployed (or if something is/was changed in XQuery and session is/was activated) + - pre-compile/execute Xquery with dummy arguments - warm-up + +# Install + - Download latest version of application... + - Deploy it as enterprise application: _'Install this deployment as an application'_ + - Deployment Order: 20 + - Restart the OSB. + +# Development + - Build is based on the Maven + - JVM 1.8 + - in pom.xml change path for following properties: +| Plugin | README | +| wls12cHome | path to FMW WLS 12c home | +| osb12cHome | path to FMW OSB 12c home | +| common12cHome | path to FMW 12c Oracle Common home | + - mvn clean install diff --git a/src/main/assembly/ear.xml b/src/main/assembly/ear.xml new file mode 100644 index 0000000..751dd51 --- /dev/null +++ b/src/main/assembly/ear.xml @@ -0,0 +1,23 @@ + + + ear + + ear + + false + false + + + ${basedir}/src/main/ear/META-INF/weblogic-application.xml + /META-INF/ + + + ${basedir}/target/${project.artifactId}-${project.version}.jar + /APP-INF/lib/ + ${project.artifactId}.jar + + + diff --git a/src/main/ear/META-INF/application.xml b/src/main/ear/META-INF/application.xml new file mode 100644 index 0000000..6225051 --- /dev/null +++ b/src/main/ear/META-INF/application.xml @@ -0,0 +1,10 @@ + + + + osb12c-xquery-warmup + + /APP-INF/lib/osb12c-xquery-warmup.jar + + \ No newline at end of file diff --git a/src/main/ear/META-INF/weblogic-application.xml b/src/main/ear/META-INF/weblogic-application.xml new file mode 100644 index 0000000..085284e --- /dev/null +++ b/src/main/ear/META-INF/weblogic-application.xml @@ -0,0 +1,12 @@ + + + + + + com.tomecode.oracle.osb12c.warmup.OsbXqueryWamUpLifecycleListener + + + \ No newline at end of file diff --git a/src/main/java/com/tomecode/oracle/osb12c/warmup/OsbXqueryWamUpLifecycleListener.java b/src/main/java/com/tomecode/oracle/osb12c/warmup/OsbXqueryWamUpLifecycleListener.java new file mode 100644 index 0000000..9f6a041 --- /dev/null +++ b/src/main/java/com/tomecode/oracle/osb12c/warmup/OsbXqueryWamUpLifecycleListener.java @@ -0,0 +1,54 @@ +package com.tomecode.oracle.osb12c.warmup; + +import java.security.PrivilegedExceptionAction; + +import com.bea.wli.config.ConfigService; +import com.bea.wli.config.spi.ResourceLifecycleListener; +import com.bea.wli.sb.ALSBConfigService; + +import weblogic.application.ApplicationLifecycleEvent; +import weblogic.application.ApplicationLifecycleListener; +import weblogic.logging.NonCatalogLogger; + +/** + * Application listener + * + * @author Tome + * + */ +public final class OsbXqueryWamUpLifecycleListener extends ApplicationLifecycleListener { + + private static final NonCatalogLogger logger = new NonCatalogLogger("OsbXqueryWarmUpListener"); + + public final void postStart(ApplicationLifecycleEvent evt) { + + try { + + weblogic.security.Security.runAs(weblogic.security.SubjectUtils.getAnonymousUser(), new PrivilegedExceptionAction() { + + @Override + public final Object run() throws Exception { + + ConfigService configService = ALSBConfigService.get().getConfigService(); + + boolean exists = false; + for (ResourceLifecycleListener listener : configService.getResourceLifecycleListeners()) { + if (listener instanceof XqueryWarmUp) { + exists = true; + } + } + + if (!exists) { + // register new listener + configService.registerResourceLifecycleListener(new XqueryWarmUp()); + logger.info("OSB XQuery Warm-Up was registered in OSB!"); + } + return null; + } + }); + } catch (Exception e) { + logger.error("Faile registed OSB XQuery Warm-Up listener in OSB, reason: " + e.getMessage(), e); + } + + } +} diff --git a/src/main/java/com/tomecode/oracle/osb12c/warmup/Utils.java b/src/main/java/com/tomecode/oracle/osb12c/warmup/Utils.java new file mode 100644 index 0000000..5e0d24c --- /dev/null +++ b/src/main/java/com/tomecode/oracle/osb12c/warmup/Utils.java @@ -0,0 +1,74 @@ +package com.tomecode.oracle.osb12c.warmup; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.xmlbeans.XmlObject; + +import com.bea.wli.config.Ref; + +/** + * Utilities + * + * @author Tome + * + */ +public final class Utils { + /** + * dummy empty message + */ + public static final XmlObject DUMMY_MESSAGE = dummyMessage(); + + private static final XmlObject dummyMessage() { + try { + return XmlObject.Factory.parse(""); + } catch (Exception e) { + throw new RuntimeException("Failed to unitialize dummmy body!, reason: " + e.getMessage(), e); + } + } + + /** + * format delta time + * + * @param td + * @return + */ + public static final String formatDeltaTime(long td) { + td = td / 1000; + int h = (int) (td / (3600)); + int m = (int) ((td - (h * 3600)) / 60); + int s = (int) (td - (h * 3600) - m * 60); + return String.format("%02d:%02d:%02d", h, m, s); + } + + /** + * split array of refs to sub-arrays + * + * @param originalArray + * @param chunkSize + * @return + */ + public static final List splitRefs(Ref[] originalArray, int chunkSize) { + List listOfArrays = new ArrayList(); + int totalSize = originalArray.length; + if (totalSize < chunkSize) { + chunkSize = totalSize; + } + int from = 0; + int to = chunkSize; + + while (from < totalSize) { + Ref[] partArray = Arrays.copyOfRange(originalArray, from, to); + listOfArrays.add(partArray); + + from += chunkSize; + to = from + chunkSize; + if (to > totalSize) { + to = totalSize; + } + } + return listOfArrays; + } + +} diff --git a/src/main/java/com/tomecode/oracle/osb12c/warmup/XqueryWarmUp.java b/src/main/java/com/tomecode/oracle/osb12c/warmup/XqueryWarmUp.java new file mode 100644 index 0000000..5c9dd48 --- /dev/null +++ b/src/main/java/com/tomecode/oracle/osb12c/warmup/XqueryWarmUp.java @@ -0,0 +1,283 @@ +package com.tomecode.oracle.osb12c.warmup; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.xml.namespace.QName; +import javax.xml.xquery.XQException; +import javax.xml.xquery.XQItemType; +import javax.xml.xquery.XQSequenceType; + +import com.bea.wli.common.xquery.XQExecOptions; +import com.bea.wli.common.xquery.x2004.iterators.NullIterator; +import com.bea.wli.config.Ref; +import com.bea.wli.config.resource.ChangeDescriptor; +import com.bea.wli.config.resource.ChangeDescriptor.Create; +import com.bea.wli.config.resource.ChangeDescriptor.Delete; +import com.bea.wli.config.resource.ChangeDescriptor.IdentityChange; +import com.bea.wli.config.resource.ChangeDescriptor.Update; +import com.bea.wli.config.resource.ChangeDescriptor.UpdateAndIdentityChange; +import com.bea.wli.config.spi.ResourceLifecycleListener; +import com.bea.wli.sb.resources.config.XqueryEntryDocument; +import com.bea.wli.sb.resources.xquery.XqueryExecutor; +import com.bea.wli.sb.resources.xquery.XqueryRepository; +import com.bea.wli.sb.resources.xquery.x10.XqueryExecutorImpl; + +import weblogic.logging.NonCatalogLogger; +import weblogic.xml.query.xdbc.XQType; + +/** + * This class is a listener for OSB resources - XQuery, is activated when + * something has changed in XQuery or when the server was started or when XQuery + * was deployed. + * + * + * Listener, create at least one new thread which call/execute/warm-up all + * changed/deployed XQuery functions/files with dummy arguments. + * + * @author Tome + * + */ +public final class XqueryWarmUp extends ResourceLifecycleListener { + + private static final NonCatalogLogger logger = new NonCatalogLogger("XqueryWarmUp"); + private static int CHUNK_SIZE = Integer.parseInt(System.getProperty("OSb.XqueryWarmUp.initChunkSize", "200")); + + public XqueryWarmUp() { + super(true, (Set) new HashSet(Arrays.asList(new String[] { "Xquery", })), true); + } + + @Override + public final void beginChangeNotification(String arg0, @SuppressWarnings("rawtypes") Map arg1) throws Exception { + + } + + @Override + public final void beginLoadNotification(String arg0, @SuppressWarnings("rawtypes") Map arg1) { + + } + + @Override + public final void changesCommitted(String arg0, @SuppressWarnings("rawtypes") Map map) { + deploymentWarmUp(map); + } + + @Override + public final void changesRolledback(String arg0, @SuppressWarnings("rawtypes") Map arg1) { + + } + + @Override + public final void endChangeNotification(String arg0, @SuppressWarnings("rawtypes") Map arg1) throws Exception { + + } + + @Override + public final void endLoadNotification(String arg0, @SuppressWarnings("rawtypes") Map arg1) { + logger.info("Warm-up..."); + Ref[] xqRefs = filterRefs(); + wampUp(xqRefs); + } + + @Override + public final void onCreate(String arg0, Create arg1, @SuppressWarnings("rawtypes") Map arg2) throws Exception { + + } + + @Override + public final void onDelete(String arg0, Delete arg1, @SuppressWarnings("rawtypes") Map arg2) throws Exception { + + } + + @Override + public final void onIdentityChange(String arg0, IdentityChange arg1, @SuppressWarnings("rawtypes") Map arg2) throws Exception { + + } + + @Override + public final void onLoad(String arg0, Create arg1, @SuppressWarnings("rawtypes") Map arg2) { + + } + + @Override + public final void onUpdate(String arg0, Update arg1, @SuppressWarnings("rawtypes") Map arg2) throws Exception { + + } + + @Override + public final void onUpdateAndIdentityChange(String arg0, UpdateAndIdentityChange arg1, @SuppressWarnings("rawtypes") Map arg2) throws Exception { + + } + + private final Ref[] filterRefs() { + Set xqRefs = XqueryRepository.get().getRefs(null); + Ref[] refs = new Ref[xqRefs.size()]; + xqRefs.toArray(refs); + return refs; + } + + /** + * warm-up XQuery which was deployed or changed (activte OSB session) + * + * @param map + */ + private final void deploymentWarmUp(@SuppressWarnings("rawtypes") Map map) { + List refs = new ArrayList(); + if (map != null) { + Iterator ik = map.keySet().iterator(); + while (ik.hasNext()) { + Object k = ik.next(); + Object v = map.get(k); + + if (v instanceof ArrayList) { + ArrayList va = (ArrayList) v; + + for (Object ai : va) { + if (ai instanceof ChangeDescriptor) { + ChangeDescriptor changeDescriptor = (ChangeDescriptor) ai; + + if ("Xquery".equals(changeDescriptor.getRef().getTypeId())) { + refs.add(changeDescriptor.getRef()); + } + } + } + } + } + } + + Ref[] xqRefs = new Ref[refs.size()]; + refs.toArray(xqRefs); + wampUp(xqRefs); + } + + /** + * wamp-up xqries when server is started + * + * @param xqRefs + */ + private final void wampUp(Ref[] xqRefs) { + // split all references to chunks and for each chunk will be created + // dedicated thread + final List chunksForThreads = Utils.splitRefs(xqRefs, CHUNK_SIZE); + + logger.info("WarmUp XQueries - Total count: " + xqRefs.length + " WarmUp was divide into chunks: " + CHUNK_SIZE + " and threads: " + chunksForThreads.size()); + + doIt(chunksForThreads); + } + + private final void doIt(final List chunksForThreads) { + final XqueryRepository repository = XqueryRepository.get(); + + ExecutorService executorService = Executors.newFixedThreadPool(chunksForThreads.size()); + for (int i = 0; i <= chunksForThreads.size() - 1; i++) { + final Ref[] refs = chunksForThreads.get(i); + + executorService.submit(new Runnable() { + + @Override + public final void run() { + warmUpXquery(refs); + } + + private final void warmUpXquery(Ref[] refs) { + long timeStart = System.currentTimeMillis(); + for (int i = 0; i <= refs.length - 1; i++) { + Ref ref = refs[i]; + logger.info("WarmUp XQuery (" + i + "): " + ref.getFullName()); + + try { + + XqueryEntryDocument xqEntiry = repository.getEntry(ref); + XqueryExecutor xqExecutor = repository.getExecutor(ref); + if (!xqEntiry.getXqueryEntry().getIsLibrary()) { + String version = repository.getVersion(ref); + Map args = new HashMap(); + if ("1.0".equals(version)) { + dummyArgumentsX10(((XqueryExecutorImpl) xqEntiry).getXQTypes(), args); + } else { + dummyArgumentsX2004(((com.bea.wli.sb.resources.xquery.x2004.XqueryExecutorImpl) xqEntiry).getXQTypes(), args); + } + XQExecOptions xqExecOptions = new XQExecOptions(); + xqExecOptions.setCopyXml(true); + xqExecutor.executeXmlObject(args, xqExecOptions); + } + } catch (Exception e) { + logger.error("Failed to WarmUp XQuery (" + i + "): " + ref.getFullName() + " reason: " + e.getMessage(), e); + } + } + + long timeEnd = System.currentTimeMillis(); + long delta = timeEnd - timeStart; + logger.info("WarmUp XQueries - Total time: " + Utils.formatDeltaTime(delta)); + } + + /** + * prepare dummy arguments for x10 + * + * @param xqTypes + * @param args + * @throws XQException + */ + private final void dummyArgumentsX10(Map xqTypes, Map args) throws XQException { + for (Entry e : xqTypes.entrySet()) { + if (e.getValue().getItemType().getBaseType() == XQItemType.XQBASETYPE_BOOLEAN) { + args.put(e.getKey(), true); + } else if (e.getValue().getItemType().getBaseType() == XQItemType.XQBASETYPE_INTEGER) { + args.put(e.getKey(), 0); + } else if (e.getValue().getItemType().getBaseType() == XQItemType.XQBASETYPE_DECIMAL) { + args.put(e.getKey(), 0d); + } else if (e.getValue().getItemType().getBaseType() == XQItemType.XQITEMKIND_TEXT) { + args.put(e.getKey(), ""); + } else { + args.put(e.getKey(), Utils.DUMMY_MESSAGE); + } + } + } + + /** + * prepare dummy arguments for XQ2004 + * + * @param xqTypes + * @param args + * @throws Exception + */ + private final void dummyArgumentsX2004(Map xqTypes, Map args) throws Exception { + + for (Entry e : xqTypes.entrySet()) { + if (e.getValue().isNode()) { + args.put(e.getKey(), Utils.DUMMY_MESSAGE); + } else { + String type = e.getValue().qname().toString(); + if (type.endsWith("string]")) { + args.put(e.getKey(), ""); + } else if (type.endsWith("double]")) { + args.put(e.getKey(), 0d); + } else if (type.endsWith("long]")) { + args.put(e.getKey(), 0l); + } else if (type.endsWith("integer]")) { + args.put(e.getKey(), 1); + } else if (type.endsWith("boolean]")) { + args.put(e.getKey(), true); + } else { + args.put(e.getKey(), new NullIterator()); + } + } + + } + + } + + }); + } + + } +}