2023-02-21

Spring Boot: Application Event Lifecycle

 With @EventListener, we can quickly turn a component's method into an event listener. Spring Boot has some predefined events we can tap into; they mark milestones in the application lifecycle.

  1. ApplicationStartingEvent
    Only the bootstrap context has been created, and "java.awt.headless" is turned off unless explicitly enabled externally.
  2. ApplicationEnvironmentPreparedEvent
    The environment sources are parsed and configured.
    Now you still have the opportunity to alter the environment, as the binding is a later step.
  3. ApplicationContextInitializedEvent
    Context is prepared, the environment is applied, and initializers have been executed. After this event, the bootstrap context is discarded.
  4. ApplicationPreparedEvent
    Beans were loaded, the magic happened.
  5. ApplicationStartedEvent
    The application context is refreshed, and we're alive.
    After this event is published, the liveness state is set to "correct" since there were no failures during initialization.
  6. On error between steps 2-5, an ApplicationFailedEvent is published before the shutdown hook is executed.
  7. ApplicationReadyEvent
    The startup is done, measurements are taken, startup info is logged, and runners are executed (command line or job). The readiness state is set to "accepting traffic" to let external actors know we're online.
After the started event, not much happens that affect us if we are making a standard application, so if we want to load some data that we couldn't or wouldn't initialize lazily on its own service, this is the spot.

2022-05-04

Java Memory Usage Optimization

So there is this not really well-known but existing memory usage optimization that changes how Glibc allocated thread-specific memory.

There is this guy who wrote the best roundup I found on the net so far: Major Bug in glibc is Killing Applications With a Memory Limit. I strongly suggest reading it.

For now, let me just quote the important part:

Long story short, this is due to a bug in malloc(). Well, it’s not a bug it’s a feature.

malloc() preallocates large chunks of memory, per thread. This is meant as a performance optimization, to reduce memory contention in highly threaded applications.

In 32 bits runtime, it can preallocate up to 2 * 64 MB * cores.

In 64 bits runtime, it can preallocate up to 8 * 64 MB * cores.

So the math is like: _NPROCESSORS_ONLN * $MALLOC_ARENA_MAX * Arena Size

Bonus content: As getconf _NPROCESSORS_ONLN returns the same as nproc output (well, almost, because nproc returns sysconf(_SC_NPROCESSORS_CONF)), if you are using a container engine like Kubernetes, this equation will use the node's core count, not the CPU shares allowed by cgroups to the pod.

Where do those numbers come from? check here: https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html

Arena Size is usually 64MB. Why is this a problem?

The first malloc in each thread triggers a 128MB mmap which typically is the initialization of thread-local storage.

-- https://bugs.openjdk.java.net/browse/JDK-8193521

For every thread created, a new arena is allocated. But even if you don't make any threads, the preallocation happens using the equation above. Huge memory waste.

If creating more arenas is denied, the thread instead writes to "main" arena or the native program heap, which is unbounded.

(Main arena can grow via brk()/sbrk())

So the most useful solution is to set the environment variable MALLOC_ARENA_MAX to a small value, like 4.

2021-01-17

In This Case...

Text camelCase PascalCase snake_case kebab-case
Save And Flush saveAndFlush SaveAndFlush save_and_flush save-and-flush
Is Valid isValid IsValid is_valid is-valid

2020-04-20

Spring: Implicit CLOB to String

So you have a stored procedure, which has an OUT parameter, with the type of CLOB.
You want to get the contents. It seems easy, right?

Well, you just need to actually ask Hibernate to turn it into a String for you in one easy step, using org.hibernate.type.MaterializedClobType:

PROCEDURE that_one_procedure(
    P_ARG1        IN  VARCHAR2,
    P_ARG2        IN  VARCHAR2,
    P_ARG3        IN  VARCHAR2,
    X_SOME_OUTPUT OUT NOCOPY CLOB
);

// Excerpt of an Entity class...
import org.hibernate.type.MaterializedClobType;

@NamedStoredProcedureQuery(name = "querySomeProcedure", procedureName = "MY_PACKAGE.THAT_ONE_PROCEDURE",
 parameters = {
   @StoredProcedureParameter(name = "P_ARG1", 
     type = String.class),
   @StoredProcedureParameter(name = "P_ARG2", 
     type = String.class),
   @StoredProcedureParameter(name = "P_ARG3", 
     type = String.class),
   @StoredProcedureParameter(name = "X_SOME_OUTPUT", 
     mode = ParameterMode.OUT, 
     type = MaterializedClobType.class) /* <-- !!! */

Now my Repository can look like this:
// Excerpt of a Repository...
@Procedure(name = "querySomeProcedure", outputParameterName = "X_SOME_OUTPUT")
 String querySomeProcedure(@Param("P_ARG1") String someArg,
   @Param("P_ARG2") String thatAnotherArg,
   @Param("P_ARG3") String alsoAnArg);

See, all the magic is done by Hibernate.

2019-07-31

Oracle: JDBC Auto-Commit is On by Default

Ever wondered what's the default on this?

Well, here it is: JDBC Developer's Guide

Scroll to section C.2.1 Disabling Auto-Commit Mode, and it says:
By default, new connection objects are in auto-commit mode.

2019-01-10

JDeveloper: JboConfigUtil Exception

So you were tinkering with JDeveloper (any version), and while trying to use an online database for your new entity / whatever, you instead got this:

SEVERE: null at oracle.jbo.dt.objects.config.JboConfigUtil.getConfigurationNameList(JboConfigUtil.java:235)
java.lang.NullPointerException
 at oracle.jbo.dt.objects.config.JboConfigUtil.getConfigurationNameList(JboConfigUtil.java:235)
 at oracle.jbo.dt.objects.config.JboConfigUtil.getConfigurationNameList(JboConfigUtil.java:225)
 at oracle.jbo.dt.jdevx.ui.pkg.XPKConnectPanel.updateConfigurations(XPKConnectPanel.java:703)
 at oracle.jbo.dt.jdevx.ui.pkg.XPKConnectPanel.onFinish(XPKConnectPanel.java:684)
 at oracle.jbo.dt.ui.main.dlg.DtuWizardPanelDialog.okAction(DtuWizardPanelDialog.java:362)
 at oracle.jbo.dt.ui.main.dlg.DtjDialog.dismissDialog(DtjDialog.java:221)
 (...)

You've already created the data source, set it in Project Properties [on the model project] / ADF Business Components, reported the feedback, saw it will be fixed in JDeveloper 13... but until then:

Go to the .jpx file of your model project (the file with the two cogwheels icon), General / Connection, select the connection.

2018-09-18

Chrome 69: Revert the ugly UI to normal

Is the new Chrome ugly as hell?

Go to chrome://flags/#top-chrome-md

Change "UI Layout for the browser's top chrome" to "Normal". Relaunch.

If it still won't change back to normal, disable this: "Use all upcoming UI features".

If still no luck, you need to disable also this: "New Tab Page Material Design Icons" chrome://flags/#ntp-icons

2018-07-03

Some Court Rulings from the Past

Ever wondered why people can resell OEM licences?

This is why: "An author of software cannot oppose the resale of his ‘used’ licences allowing the use of his programs downloaded from the internet"

Sources:
1. Court of Justice of the European Union - Press Release
2. Judgment of the Court


2018-04-19

Java 8: JDBC ResultSet to Stream

Streams API is a gift.
But JDBC is still the old-school one.
Let's wrap it!

package org.example.jdbc.stream;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public final class StreamHelper {
    public static class Record {
        private final Map<String, Object> fields = new HashMap<>(16);
        private final long count;

        private Record(final ResultSet resultSet) throws SQLException {
            final ResultSetMetaData metaData = resultSet.getMetaData();
            count = metaData.getColumnCount();
            for (int i = 1; i <= count; ++i) {
                fields.put(metaData.getColumnName(i), resultSet.getObject(i));
            }
        }

        /**
         * Is there a column named like this?
         *
         * @param columnName is the column name in the query.
         * @return True if found.
         */
        public boolean contains(final String columnName) {
            return fields.containsKey(columnName);
        }

        /**
         * Number of columns.
         *
         * @return Numer of columns.
         */
        public long count() {
            return count;
        }

        /**
         * Get value casted to the requested type.
         * <p>
         * No type checking happens inside. It is your job to know the datatype in the database.
         * <p>
         * Example:<br>
         * {@code record.get("COLUMN1", Long.class); // returns a Long}
         *
         * @param columnName is the column name in the query.
         * @param type is Java type of the column.
         * @return The value casted to the Java type.
         */
        public <T> T get(final String columnName, final Class<T> type) {
            return type.cast(getObject(columnName));
        }

        /**
         * Get columns in the record.
         *
         * @return Collection of the column names.
         */
        public Set<String> getColumns() {
            return Collections.unmodifiableSet(fields.keySet());
        }

        /**
         * Get value as an object.
         *
         * @param columnName is the column name in the query.
         * @return The value.
         */
        public Object getObject(final String columnName) {
            return fields.get(columnName);
        }

        /**
         * Get value as string.
         *
         * @param columnName is the column name in the query.
         * @return Value as string.
         */
        public String getString(final String columnName) {
            return Objects.toString(fields.get(columnName));
        }

        /**
         * Is the given cell null?
         *
         * @param columnName is the column name in the query.
         * @return True if null.
         */
        public boolean isNull(final String columnName) {
            return getObject(columnName) == null;
        }

        @Override
        public String toString() {
            return fields.entrySet().stream().map(e -> e.getKey() + ": " + e.getValue())
                    .collect(Collectors.joining(", "));
        }
    }

    /**
     * Wrap a ResultSet in a Stream.
     * <p>
     * The wrapper consumes the result set. The caller must close the result set after the stream
     * processing was finished.
     *
     * @param resultSet is the open result set to streamline.
     * @return A stream of rows.
     */
    public static Stream<Record> asStream(final ResultSet resultSet) {
        // "est = Long.MAX_VALUE if infinite, unknown, or too expensive to compute."
        return StreamSupport.stream(new Spliterators.AbstractSpliterator<Record>(Long.MAX_VALUE,
                Spliterator.NONNULL | Spliterator.IMMUTABLE) {
            @Override
            public boolean tryAdvance(final Consumer<? super Record> action) {
                try {
                    if (!resultSet.next()) {
                        return false;
                    }
                } catch (@SuppressWarnings("unused") final SQLException e) {
                    return false;
                }
                try {
                    action.accept(new Record(resultSet));
                } catch (@SuppressWarnings("unused") final SQLException e) {
                    return false;
                }
                return true;
            }
        }, true).parallel();
    }

    private StreamHelper() { /* Hidden. */ }
}
Usage example:
import org.example.jdbc.stream.StreamHelper;
import org.example.jdbc.stream.StreamHelper.Record;
// ...
    @GET
    @Path("test")
    public Response test() {
        try (Connection connection = Database.connect();
                Statement statement = connection.createStatement();
                ResultSet resultSet = statement.executeQuery("SELECT * FROM MY_TABLE")) {
            return Response.ok(StreamHelper.asStream(resultSet).map(Record::toString)
                    .collect(Collectors.joining(", "))).build();
        } catch (final SQLException | NamingException e) {
            return Response.serverError().entity(e.toString()).build();
        }
    }

2018-04-05

Java EE7 ScheduledManagedExecutorService



 CustomWorkManager
 
  MINTHREAD
  10
 
 
  MAXTHREAD
  150
 
 
  MAXCAPACITY
  10000
 



 FooSMES
 CustomWorkManager
 10



 concurrent/FooSMES
 FooSMES



 concurrent/FooSMES
 javax.enterprise.concurrent.ManagedScheduledExecutorService

ScheduledExecutorService mySMES = InitialContext.doLookup("java:comp/env/concurrent/FooSMES");

ScheduledFuture<?> future = mySMES.scheduleAtFixedRate(SomeClass::someMethod, 0, 5, TimeUnit.MINUTES);
// Starts immediately (delay 0 minutes), run every 5 minutes.

// How to stop:
if (!future.isCancelled()) {
 future.cancel(true);
}
// true == If the Runnable is running at the moment, the Thread will likely receive an interrupt.
// Inside SomeClass's someMethod method.

// How to handle thread interruption:
// 1) Periodically check Thread.interrupted(). If it's true, please quickly clean up, and then return.
// 2) catch InterruptedException -- this is not available at all places.

// Example:
while(!Thread.interrupted()) {
 // Do repetitive tasks that took very long if you consider all the iterations combined.
}
// We get here when interrupted. Clean up everything and leave.

2018-04-04

Oracle: Safe, Inline, is_numeric Check

So there was a character column, but I wanted to get the rows where it is not actually a number.

TO_NUMBER(REGEXP_SUBSTR(MY_COLUMN, '^\d+')) IS NULL

If the input is empty, it will return null. When will the input be empty? If the cell is a not number-only string.

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();