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!)