2017-12-28

Java EE7 ManagedExecutorService

So you have a WebLogic and want to try out the fancy "new" feature of having managed threads.

Have the ExecutorService configured first in weblogic.xml.
<!-- weblogic.xml -->
<managed-executor-service>
 <name>CustomMES</name>
 <max-concurrent-long-running-requests>10</max-concurrent-long-running-requests>
</managed-executor-service>
<resource-env-description>
 <resource-env-ref-name>concurrent/CustomMES</resource-env-ref-name>
 <resource-link>CustomMES</resource-link>
</resource-env-description>

Then name it in web.xml.
<!-- web.xml -->
<resource-env-ref>
 <resource-env-ref-name>concurrent/CustomMES</resource-env-ref-name>
 <resource-env-ref-type>javax.enterprise.concurrent.ManagedExecutorService</resource-env-ref-type>
</resource-env-ref>

Now, you can ask for it.
public static ExecutorService getExecutorService() {
 try {
  // Get our own, defined in weblogic.xml
  return InitialContext.doLookup("java:comp/env/concurrent/CustomMES");
 } catch (final NamingException e) {}
 try {
  // Fallback level 1: Get the Java EE 7 default MES
  return InitialContext.doLookup("java:comp/DefaultManagedExecutorService");
 } catch (final NamingException e) {}
 // Fallback level 2: Return the default pool. 
 // This always exists. In fact, every Java8 threaded feature uses this.
 return ForkJoinPool.commonPool();
}
In the latter case, you could use the @Resource annotation with the mappedBy attribute, if you have properly configured beans.

The ExecutorService is already an Executor, so you can pass it to eg. a CompletableFuture:
CompletableFuture<void> future = CompletableFuture
            .supplyAsync(Frobolator::aSupplier, getExecutorService())
            .thenAccept(result -> bar(result));

// Later, wait for the Future, if necessary.
future.join();

But properly usingCompletableFutures are another topic...

Implementation of the ManagedExecutorService in WebLogic is here: $ORACLE_HOME\wlserver\modules\com.oracle.weblogic.concurrent.jar

2017-11-13

JDeveloper: bindingContext.findDataControl deprecated

You get a warning, that says:
Warning: findDataControl(java.lang.String) in oracle.adf.model.BindingContext has been deprecated.
So you need another, up-to-date way to get your data control.
Try this:

private static ApplicationModuleImpl getAppModuleImpl(final String dataControlName) {
    final FacesContext fc = FacesContext.getCurrentInstance();
    final ELContext elContext = fc.getELContext();
    final ExpressionFactory elFactory = fc.getApplication().getExpressionFactory();
    final ValueExpression valueExp = elFactory.createValueExpression(elContext, "#{data." + dataControlName + ".dataProvider}", ApplicationModuleImpl.class);
    return (ApplicationModuleImpl) valueExp.getValue(elContext);
}

Usually, the data control name is like {Application Module name} + "DataControl".
Hard to find? Look into DataBindings.cpx and look for BC4JDataControl elements id attribute.

What's that data literal there? That's oracle.adf.model.BindingContext.CONTEXT_ID hardcoded.

2017-11-10

Java: Jersey-server Async

Have you heard about Jersey's @ManagedAsync annotation?

What does it give? Well, it automagically runs the resource method in a separate thread, hosted by Jersey's own ExecutorService.
This way you don't have to do a boilerplate executor pattern for your every resource method.

When is this useful: If you expect blocking IO during handling the request, this way you can easily offload the execution into a different thread that can block as much as it wants.

For beautiful examples, see this blog post.

2017-10-30

ICS: Cannot Activate Integration

So I recently used Oracle's Integration Cloud Service, and I couldn't activate an integration. It said:
com.bea.wli.sb.transports.TransportException: Failed to create JCABindingReference for wsdl: servicebus:/MYINTGR_01/Resources/resources/application_24/inbound_25/resourcegroup_26/invoke1_REQUEST.wsdl, operation: invoke1_REQUEST, exception: BINDING.JCA-12600
Generic error.
JCA binding runtime error.
Cause: {0}.

Turned out, the Connectivity (or On-Premise) Agent on the on-premise DB crashed and the ICS couldn't fetch metadata for creating the web service.

Contact your admin to restart the agent.

2017-10-25

JDeveloper: Build Does Not Find File That Dont Even Exist


Your build fails, as JDev cannot copy a file that does not even exist? The JDeveloper's IDE Performance Cache is playing you.

Simple solution:

  1. Exit JDeveloper
  2. Delete the .data folder inside your app folder.
  3. Profit!
If it's not there, see the source for detailed info.

Source (Thanks, Andrejus!)

2017-09-14

Authentication - Authorization - Adjudication

1. Authentication (AuthN)

Authenticates you. Are you really _You_? This is the part where the page asks you for your credentials (username+password, client-cert, &c) or the patrolman asks for your ID.

2.1. Authorization (AuthZ)

After establishing your identity (AuthN), determining if you can access the given resource or not. This is the part when the patrolman asks for your driving license.

2.2. Adjudication

If there are multiple AuthZ providers, the adjudicator decides which one takes precedence. This is the part when the patrolman weights pieces of information, like 1) you do have a driving license, 2) it is revoked or not, 3) you are disqualified or not, and 4) whether you are taking your sick grandma to the hospital or not.

2017-08-30

Weblogic: JAR entry META-INF/adfm.xml not found in _wl_cls_gen.jar

You've just deployed your favorite EAR in a WebLogic successfully, but when you open it, an unfriendly HTTP 500 greets you. This usually happens in development mode.
Error 500--Internal Server Error

oracle.jbo.JboException: JBO-29114 ADFContext is not setup to process messages for this exception. Use the exception stack trace and error code to investigate the root cause of this exception. Root cause error code is JBO-29000. Error message parameters are {0=java.io.FileNotFoundException, 1=JAR entry META-INF/adfm.xml not found in C:\Users\yolo\AppData\Roaming\JDeveloper\system12.2.1.2.42.170105.1224\DefaultDomain\servers\DefaultServer\tmp\_WL_user\OalCdqWorkbench\dfoxis\war\WEB-INF\lib\_wl_cls_gen.jar}
 at oracle.jbo.uicli.mom.CpxUtils.getCpxListFromMetadata(CpxUtils.java:512)
 at oracle.jbo.uicli.mom.JUMetaObjectManager.loadCpx(JUMetaObjectManager.java:915)
 at oracle.adf.model.BindingContext.initialize(BindingContext.java:469)
 at oracle.adf.model.BindingRequestHandler.beginRequest(BindingRequestHandler.java:270)
 at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:196)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
 at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:105)
 at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:529)
 at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
 at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:529)
 at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:354)
 at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:232)
 at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
 at oracle.adf.library.webapp.LibraryFilter.doFilter(LibraryFilter.java:169)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
 at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:141)
 at java.security.AccessController.doPrivileged(Native Method)
 at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
 at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:650)
 at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:124)
 at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:232)
 at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:94)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
 at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:248)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
 at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:32)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
 at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3683)
 at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3649)
 at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:326)
 at weblogic.security.service.SecurityManager.runAsForUserCode(SecurityManager.java:197)
 at weblogic.servlet.provider.WlsSecurityProvider.runAsForUserCode(WlsSecurityProvider.java:203)
 at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:71)
 at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2433)
 at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2281)
 at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2259)
 at weblogic.servlet.internal.ServletRequestImpl.runInternal(ServletRequestImpl.java:1691)
 at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1651)
 at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:270)
 at weblogic.invocation.ComponentInvocationContextManager._runAs(ComponentInvocationContextManager.java:348)
 at weblogic.invocation.ComponentInvocationContextManager.runAs(ComponentInvocationContextManager.java:333)
 at weblogic.work.LivePartitionUtility.doRunWorkUnderContext(LivePartitionUtility.java:54)
 at weblogic.work.PartitionUtility.runWorkUnderContext(PartitionUtility.java:41)
 at weblogic.work.SelfTuningWorkManagerImpl.runWorkUnderContext(SelfTuningWorkManagerImpl.java:640)
 at weblogic.work.ExecuteThread.execute(ExecuteThread.java:406)
 at weblogic.work.ExecuteThread.run(ExecuteThread.java:346)
Caused by: java.io.FileNotFoundException: JAR entry META-INF/adfm.xml not found in C:\Users\yolo\AppData\Roaming\JDeveloper\system12.2.1.2.42.170105.1224\DefaultDomain\servers\DefaultServer\tmp\_WL_user\OalCdqWorkbench\dfoxis\war\WEB-INF\lib\_wl_cls_gen.jar
 at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:142)
 at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:150)
 at java.net.URL.openStream(URL.java:1045)
 at oracle.adf.share.common.rc.util.impl.MetadataRegistryImpl.openStream(MetadataRegistryImpl.java:650)
 at oracle.adf.share.common.rc.util.impl.MetadataRegistryImpl.getDomDocument(MetadataRegistryImpl.java:665)
 at oracle.adf.share.common.rc.util.impl.MetadataRegistryImpl.getRegistryPaths(MetadataRegistryImpl.java:247)
 at oracle.adf.share.common.rc.util.impl.MetadataRegistryImpl.visitRegistryPaths(MetadataRegistryImpl.java:160)
 at oracle.adf.share.common.rc.util.impl.MetadataRegistryImpl.visitRegistryPaths(MetadataRegistryImpl.java:116)
 at oracle.jbo.uicli.mom.CpxUtils.getCpxListFromMetadata(CpxUtils.java:491)
 ... 46 more

What to do: Restart WebLogic.

The issue is handled here: https://support.oracle.com/knowledge/Middleware/2244836_1.html
This is a caching issue, so to permanently fix it, upgrade your JDeveloper.

Javascript: Display Image Fetched Through Authenticated REST API

I have a protected REST endpoint in Oracle Content and Experience Cloud, which returns image/png. Let's display it.

var imgUrl = "https://foo.barcloud.com/documents/api/latest/files/FA5A98CDC6482BD3ED6CFEA98CD980E/data/thumbnail";
var user = "foobar";
var pass = "Yolo6969";

// @see https://stackoverflow.com/a/17682424/357403

var xhr = new XMLHttpRequest();

// Success
xhr.addEventListener("load", function __xhrLoaded() {
    var img = document.getElementById('thumbnail');
    // This will create the DataURI for us.
    var URL = window.URL || window.webkitURL;

    switch (this.responseType) {
    case "arraybuffer":
        // createObjectURL only accepts Blob.
        img.src = URL.createObjectURL(new Blob([ this.response ], { type : this.getResponseHeader('Content-Type') }));
        break;
    case "blob":
        img.src = URL.createObjectURL(this.response);
        break;
    default:
        console.error("Unsupported response type: ", this.responseType, " -- expected binary types for image data.");
        break;
    }
});

// Failure
xhr.addEventListener("error", function __xhrFailed() {
    console.log("Request failed.", this);
});

// open (method, uri, isAsync, user, passwd)
xhr.open('GET', imgUrl, true, user, pass);
// Yes, I want to authenticate.
xhr.withCredentials = true;
// I want to authenticate right now.
xhr.setRequestHeader("Authorization", "Basic " + btoa(user + ':' + pass));
// Give me a Blob in the `response` field.
xhr.responseType = "blob";
xhr.overrideMimeType("image/png");
// Execute the action.
xhr.send();

2017-08-23

Java: CORS Filter for Jersey

So you want to add CORS support for your Jersey server.

Add this filter:

package org.example.rest.service.filter;

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Priority;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import org.glassfish.jersey.server.ExtendedUriInfo;

@Provider
@Priority(Priorities.HEADER_DECORATOR)
public class CORSFilter implements ContainerRequestFilter, ContainerResponseFilter {
 private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
 private static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
 private static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
 private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
 private static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
 private static final String AUTHORIZATION = "authorization";
 private static final String ORIGIN = "Origin";

 private static String extractAllowedMethods(final ExtendedUriInfo extendedUriInfo) {
  final Optional<Class<?>> optional = extendedUriInfo.getMatchedRuntimeResources().stream()
    .flatMap(r -> r.getResources().stream()).flatMap(r -> r.getHandlerClasses().stream())
    .filter(r -> r.getPackage().getName().startsWith("org.example.rest.service")).findFirst();

  if (optional.isPresent()) {
   return Arrays.stream(optional.get().getDeclaredMethods())//
     .flatMap(m -> Arrays.stream(m.getAnnotations()))//
     .map(a -> a.annotationType().getAnnotation(javax.ws.rs.HttpMethod.class))//
     .filter(Objects::nonNull)//
     .map(HttpMethod::value)//
     .distinct()//
     .collect(Collectors.joining(", "));
  }
  // Returning OPTIONS is a bit shady, as ACAM is about *real*, actual methods only.
  return "OPTIONS";
 }

 @Context
 private HttpServletRequest request;

 @Context
 private ExtendedUriInfo extendedUriInfo;

 @Override
 public void filter(final ContainerRequestContext requestContext) throws IOException {
  final String origin = requestContext.getHeaderString(ORIGIN);
  if (origin != null && "OPTIONS".equals(requestContext.getMethod())) {
   request.setAttribute(this.getClass().getName(), true);
   requestContext.abortWith(Response.ok("CORS OK, carry on.", MediaType.TEXT_PLAIN_TYPE).build());
  }
 }

 /**
  * @see https://www.w3.org/TR/cors/
  * @see https://jmchung.github.io/blog/2013/08/11/cross-domain-on-jersey-restful-web-services/
  * @see https://solutionsisee.wordpress.com/2016/06/30/adding-cors-support-in-jersey-server/
  */
 @Override
 public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext)
   throws IOException {

  final MultivaluedMap<String, Object> responseHeaders = responseContext.getHeaders();
  final String origin = requestContext.getHeaderString(ORIGIN);

  if (origin != null) {
   // The presence of the Origin header marks a CORS request.
   responseHeaders.add(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
   responseHeaders.add(ACCESS_CONTROL_ALLOW_METHODS, extractAllowedMethods(extendedUriInfo));
   responseHeaders.add(ACCESS_CONTROL_ALLOW_HEADERS, AUTHORIZATION + ", X-Requested-With, Content-Type");
   if (requestContext.getHeaderString(ACCESS_CONTROL_REQUEST_HEADERS) != null) {
    responseHeaders.add(ACCESS_CONTROL_ALLOW_CREDENTIALS, requestContext
      .getHeaderString(ACCESS_CONTROL_REQUEST_HEADERS).toLowerCase().contains(AUTHORIZATION));
   }
  }

  if (request.getAttribute(this.getClass().getName()) != null) {
   // We are in a CORS Preflight answer, fast tracked. The entity (== response body) is not
   // relevant.
  }
 }
}

It is almost implementation agnostic, except for the ExtendedUriInfo.

2017-07-05

Maven: Using Oracle Archetypes with Maven in Eclipse


  1. Go here: https://community.oracle.com/docs/DOC-894569
  2. Download this file: https://maven.oracle.com/archetype-catalog.xml
    1. It will ask for your OTN login, of course.
    2. If you don't download it, you will not be able to use it.
  3. During archetype selection, click Configure... next to the Catalog drop-down.
  4. Add Local Catalog...
    1. Adding a remote catalog is not working because of the HTTP Basic auth.
  5. Choose the recently downloaded file.
  6. Do the next-next-finish magic.
  7. Voilá.
You might also need this as a reference: Configuring the Oracle Maven Repository

For the exact version of the archetype, take a ook inside: https://www.oracle.com/content/secure/maven/content/com/oracle/weblogic/archetype/basic-webapp/maven-metadata.xml