Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions org.knime.core.ui/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Export-Package: org.knime.core.ui;x-internal:=true,
org.knime.core.ui.workflowcoach.data;x-internal:=true,
org.knime.core.ui.wrapper;x-internal:=true,
org.knime.core.webui;x-internal:=true,
org.knime.core.webui.browser;x-internal:=true,
org.knime.core.webui.data;x-internal:=true,
org.knime.core.webui.data.rpc;x-internal:=true,
org.knime.core.webui.data.rpc.json.impl;x-internal:=true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@
*/
package org.knime.core.ui;

import java.util.Optional;

import org.knime.core.node.workflow.NodeContext;
import org.knime.core.ui.node.workflow.ContextObjectSupplierUI;
import org.knime.core.webui.browser.BrowserService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;

/**
* Activator for the {@code org.knime.core.ui} plugin.
Expand All @@ -60,14 +64,33 @@
*/
public class CoreUIPlugin implements BundleActivator {

private static CoreUIPlugin instance;

private ServiceTracker<BrowserService, BrowserService> m_browserServiceTracker;

@Override
public void start(final BundleContext context) throws Exception {
instance = this; // NOSONAR (static assignment)
NodeContext.addContextObjectSupplier(new ContextObjectSupplierUI());
m_browserServiceTracker = new ServiceTracker<>(context, BrowserService.class, null);
m_browserServiceTracker.open();
}

@Override
public void stop(final BundleContext context) throws Exception {
//
m_browserServiceTracker.close();
m_browserServiceTracker = null;
instance = null;

Check failure on line 83 in org.knime.core.ui/src/eclipse/org/knime/core/ui/CoreUIPlugin.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make the enclosing method "static" or remove this set.

See more on https://sonarcloud.io/project/issues?id=knime_knime-core-ui&issues=AZ0q01TloH7unNjgEigU&open=AZ0q01TloH7unNjgEigU&pullRequest=135
Comment on lines 80 to +83
}

/**
* Returns the registered {@link BrowserService}, if any.
*
* @return the browser service, or an empty {@link Optional} if none is registered
* @since 5.12
*/
public static Optional<BrowserService> getBrowserService() {
return Optional.ofNullable(instance.m_browserServiceTracker).map(ServiceTracker::getService);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* ------------------------------------------------------------------------
*
* Copyright by KNIME AG, Zurich, Switzerland
* Website: http://www.knime.com; Email: contact@knime.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 3, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*
* Additional permission under GNU GPL version 3 section 7:
*
* KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs.
* Hence, KNIME and ECLIPSE are both independent programs and are not
* derived from each other. Should, however, the interpretation of the
* GNU GPL Version 3 ("License") under any applicable laws result in
* KNIME and ECLIPSE being a combined program, KNIME AG herewith grants
* you the additional permission to use and propagate KNIME together with
* ECLIPSE with only the license terms in place for ECLIPSE applying to
* ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the
* license terms of ECLIPSE themselves allow for the respective use and
* propagation of ECLIPSE together with KNIME.
*
* Additional permission relating to nodes for KNIME that extend the Node
* Extension (and in particular that are based on subclasses of NodeModel,
* NodeDialog, and NodeView) and that only interoperate with KNIME through
* standard APIs ("Nodes"):
* Nodes are deemed to be separate and independent programs and to not be
* covered works. Notwithstanding anything to the contrary in the
* License, the License does not apply to Nodes, you are not required to
* license Nodes under the License, and you are granted a license to
* prepare and propagate Nodes, in each case even if such Nodes are
* propagated with or for interoperation with KNIME. The owner of a Node
* may freely choose the license terms applicable to such Node, including
* when such Node is propagated with or for interoperation with KNIME.
*
* ------------------------------------------------------------------------
*/
package org.knime.core.webui.browser;

import java.io.IOException;
import java.util.Optional;

import org.knime.core.ui.CoreUIPlugin;

/**
* Service for headless browser rendering. All parameters are serializable (String, byte[], int, long, boolean) so this
* interface can be exported as an OSGi Remote Service via ECF.
*
* <p>
* Callers are responsible for converting node/component views to JSON page content (e.g. via
* {@code AbstractPageManager.createWizardPageForImageGeneration}) before invoking this service.
*
* @author Martin Horn, KNIME GmbH, Konstanz, Germany
*
* @since 5.12
*/
public interface BrowserService {

/**
* Returns the highest-priority registered {@link BrowserService}, if any. The service is looked up via the OSGi
* service registry.
*
* @return the active browser service, or empty if none is registered
*/
static Optional<BrowserService> get() {
return CoreUIPlugin.getBrowserService();
}

/**
* Renders content (image or report) from a JSON web-node-page using a headless browser.
*
* @param pageJson the page content serialized as a JSON string (e.g. from
* {@code JSONWebNodePage.toJsonString()} or a report page)
* @param callbackId unique ID for result extraction (e.g. "generatedImage_&lt;uuid&gt;")
* @param width the viewport width in pixels
* @param height the viewport height in pixels
* @param timeoutMs maximum wait time in milliseconds
* @param screenshotFallback if {@code true}, captures a screenshot as fallback when the content callback times out
* (useful for image generation); if {@code false}, throws on timeout (appropriate for report generation)
* @return the rendered content (image data string or report HTML)
* @throws IOException if an error occurs during rendering
*/
String renderContent(String pageJson, String callbackId, int width, int height, long timeoutMs,
boolean screenshotFallback) throws IOException;

/**
* Converts HTML content to PDF using a headless browser.
*
* @param htmlContent the HTML document as UTF-8 bytes
* @param timeoutMs maximum wait time in milliseconds
* @return the PDF file content as bytes
* @throws IOException if an error occurs during rendering
*/
byte[] printToPdf(byte[] htmlContent, long timeoutMs) throws IOException;

/**
* Opens the given URL in a browser window. Used to drive browser-based flows (e.g.&nbsp;OAuth) from a controllable
* browser instance. The default implementation is a no-op; implementations that provide an interactive browser
* (e.g.&nbsp;the local CEF implementation) should override this method.
*
* @param url the URL to open
*/
default void openBrowserWindow(final String url) {
// no-op by default; overridden by implementations that provide an interactive browser
}
}