diff --git a/api.intent/arch.xml b/api.intent/arch.xml new file mode 100644 --- /dev/null +++ b/api.intent/arch.xml @@ -0,0 +1,1139 @@ + + +]> + + + + &api-questions; + + + +

+ This module was originally created to provide a way to handle + clicks on hyperlinks in the output window. Some more sophisticated + objects for describing intended operations can be added into this + module in the future. +

+

+ The URI-based actions are useful if the front-end and back-end of + the application is separated, e.g. in network environment. The + actions can be specified on back-end, but handled on front-end, + without any unnecessary communication. +

+ + +

+ API for invoking some intended operation, specified by + a URI. For example, for displaying a web page in browser, or for + opening a source file in editor. +

+
+ +

+ SPI for handlers that are able to invoke proper operation for + some URI. +

+
+
+ + + + + +

+ The code is checked by unit tests. +

+
+ + + + + +

+ Done. +

+
+ + + + + + +
+    IntentManager.execute(Intent.forUri(new URI("scheme://path/")));
+            
+
+ + +
+    @ServiceProvider(service = OpenUriHandler.class, position = 800)
+    public class TestOpenUriHandler implements OpenUriHandler {
+
+        public boolean open(URI uri) {
+            if ("http".equals(uri.getScheme())) {
+                // open default browser
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+            
+
+
+ + + + + +

+ This module provides a contract between API clients that can express + some intention to invoke an operation (specified e.g. by a URI) and + SPI providers that can handle the URI. +

+

+ This is useful in client-server environments, where the intention + can be constructed on server-side, but handled on client-side. The + objects that describe the intention should be easy to construct, + transfer and interpret. +

+
+ + + + + + + + + + + + +

+ No deprecation needed. +

+
+ + + + + +

+ Yes. +

+
+ + + + + +

+ No standards. +

+
+ + + + + +

+ No settings are read or written. +

+
+ + + + + +

+ 1.6 +

+
+ + + + + +

+ JRE +

+
+ + + + + + + + + + + + +

+ No non-NB dependencies. +

+
+ + + + + +

+ Any platform. +

+
+ + + + + +

+ Standard module dependency is sufficient. +

+
+ + + + + +

+ Just module JAR. +

+
+ + + + + +

+ Yes. +

+
+ + + + + +

+ Only API and SPI packages are public. +

+
+ + + + + +

+ Installation location does not matter. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ The API is threadsafe. SPI implementations should ensure proper + synchronization. +

+
+ + + + + +

+ No clipboard access. +

+
+ + + + + +

+ No Drag & Drop support. +

+
+ + + + + +

+ No files are read or written by this module. +

+
+ + + + + +

+ The lookup is used to find registered OpenUriHandlers. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ Very little memory consumed. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ Code in the module is very simple. Performance is incluenced mosly + by SPI implementations, which should run quite quickly. +

+
+ + + + + +

+ No performance criteria are enforced. The plugged-in code is invoked + by a dedicated executor. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ +
diff --git a/api.intent/build.xml b/api.intent/build.xml new file mode 100644 --- /dev/null +++ b/api.intent/build.xml @@ -0,0 +1,5 @@ + + + Builds, tests, and runs the project org.netbeans.api.intent + + diff --git a/api.intent/manifest.mf b/api.intent/manifest.mf new file mode 100644 --- /dev/null +++ b/api.intent/manifest.mf @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.netbeans.api.intent +OpenIDE-Module-Localizing-Bundle: org/netbeans/api/intent/Bundle.properties +OpenIDE-Module-Specification-Version: 1.0 + diff --git a/api.intent/nbproject/project.properties b/api.intent/nbproject/project.properties new file mode 100644 --- /dev/null +++ b/api.intent/nbproject/project.properties @@ -0,0 +1,4 @@ +is.autoload=true +javac.source=1.6 +javac.compilerargs=-Xlint -Xlint:-serial +javadoc.arch=${basedir}/arch.xml diff --git a/api.intent/nbproject/project.xml b/api.intent/nbproject/project.xml new file mode 100644 --- /dev/null +++ b/api.intent/nbproject/project.xml @@ -0,0 +1,53 @@ + + + org.netbeans.modules.apisupport.project + + + org.netbeans.api.intent + + + org.netbeans.api.annotations.common + + + + 1 + 1.25 + + + + org.openide.util.base + + + + 9.1 + + + + org.openide.util.lookup + + + + 8.26 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.nbjunit + + + + + + org.netbeans.api.intent + org.netbeans.spi.intent.uri + + + + diff --git a/api.intent/src/org/netbeans/api/intent/Bundle.properties b/api.intent/src/org/netbeans/api/intent/Bundle.properties new file mode 100644 --- /dev/null +++ b/api.intent/src/org/netbeans/api/intent/Bundle.properties @@ -0,0 +1,7 @@ +OpenIDE-Module-Display-Category=Infrastructure +OpenIDE-Module-Long-Description=\ + API for invoking intended operations (described by suitable type of object, e.g. \ + URI) by some of registered handlers.\n\ + SPI for handlers of possible intended operations. +OpenIDE-Module-Name=Intent API +OpenIDE-Module-Short-Description=Performing intended operations by suitable handlers diff --git a/api.intent/src/org/netbeans/api/intent/Intent.java b/api.intent/src/org/netbeans/api/intent/Intent.java new file mode 100644 --- /dev/null +++ b/api.intent/src/org/netbeans/api/intent/Intent.java @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.intent; + +import java.net.URI; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.spi.intent.uri.OpenUriHandler; +import org.openide.util.Parameters; + +/** + * Class that describes an intended operation. + * + * @author jhavlin + * + * @param Result type of the intended operation. + * @see IntentManager + */ +public abstract class Intent { + + abstract R invoke(); + + Intent() { + } + + /** + * Create an intended operation described by a URI. + *

+ * Result type of the operation will be a boolean value: true if the URI was + * handled, false if no provider was able to handle it. + *

+ * + * @param uri URI describing the operation. + * @return The new URI-based intended operation. + * + * @see OpenUriHandler + */ + public static Intent forUri(@NonNull URI uri) { + Parameters.notNull("uri", uri); //NOI18N + return new UriIntent(uri); + } +} diff --git a/api.intent/src/org/netbeans/api/intent/IntentManager.java b/api.intent/src/org/netbeans/api/intent/IntentManager.java new file mode 100644 --- /dev/null +++ b/api.intent/src/org/netbeans/api/intent/IntentManager.java @@ -0,0 +1,95 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.intent; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import org.openide.util.RequestProcessor; + +/** + * Manager for execution and submitting of {@link Intent}s. + * + * @author jhavlin + * @see Executor + */ +public final class IntentManager { + + private static final RequestProcessor RP = new RequestProcessor( + IntentManager.class); + + private IntentManager() { + } + + /** + * Execute an intent by an internal executor. + * + * @param intent The intent to execute. + */ + public static void execute(final Intent intent) { + RP.execute(new Runnable() { + + @Override + public void run() { + intent.invoke(); + } + }); + } + + /** + * Submit an intent to an internal executor. + * + * @param Result type of the intended operation. + * @param intent The intent to submit. + * + * @return {@link Future} object of the submitted task. + */ + public static Future submit(final Intent intent) { + return RP.submit(new Callable() { + + @Override + public T call() throws Exception { + return intent.invoke(); + } + }); + } +} diff --git a/api.intent/src/org/netbeans/api/intent/UriIntent.java b/api.intent/src/org/netbeans/api/intent/UriIntent.java new file mode 100644 --- /dev/null +++ b/api.intent/src/org/netbeans/api/intent/UriIntent.java @@ -0,0 +1,76 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.intent; + +import java.net.URI; +import org.netbeans.spi.intent.uri.OpenUriHandler; +import org.openide.util.Lookup; + +/** + * Intent described by a URI object. + * + *

+ * This is a package-private implementation returned by + * {@link Intent#forUri(java.net.URI)}. + *

+ * + * @author jhavlin + */ +class UriIntent extends Intent { + + private final URI uri; + + UriIntent(URI uri) { + this.uri = uri; + } + + @Override + Boolean invoke() { + for (OpenUriHandler handler : Lookup.getDefault().lookupAll( + OpenUriHandler.class)) { + if (handler.open(uri)) { + return true; + } + } + return false; + } +} diff --git a/api.intent/src/org/netbeans/spi/intent/uri/OpenUriHandler.java b/api.intent/src/org/netbeans/spi/intent/uri/OpenUriHandler.java new file mode 100644 --- /dev/null +++ b/api.intent/src/org/netbeans/spi/intent/uri/OpenUriHandler.java @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.spi.intent.uri; + +import java.net.URI; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.intent.Intent; +import org.openide.util.lookup.ServiceProvider; + +/** + * SPI for handlers that can process URI hyperlinks that were clicked in the + * application (or somehow invoked). + * + *

+ * This is a handler for for intents created by + * {@link Intent#forUri(java.net.URI)}. + *

+ * + * @see Intent#forUri(java.net.URI) + * @author jhavlin + */ +public interface OpenUriHandler { + + /** + * Handle the passed URI, if it is supported by this handler. + * + *

+ * To register a handler, use {@link ServiceProvider} annotation. Ensure + * that {@link ServiceProvider#position()} is set properly. + *

+ * + * @param uri The URI to open. + * + * @return True if the URI has been handled succesfully, false if this + * handler doesn't support it and thus it should be passed to next available + * handler. + * + * @see Intent#forUri(java.net.URI) + */ + boolean open(@NonNull URI uri); +} diff --git a/api.intent/test/unit/src/org/netbeans/api/intent/UriIntentTest.java b/api.intent/test/unit/src/org/netbeans/api/intent/UriIntentTest.java new file mode 100644 --- /dev/null +++ b/api.intent/test/unit/src/org/netbeans/api/intent/UriIntentTest.java @@ -0,0 +1,99 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.intent; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.junit.MockServices; +import org.netbeans.spi.intent.uri.OpenUriHandler; + +/** + * + * @author jhavlin + */ +public class UriIntentTest { + + @Test + public void testOpenUri() throws URISyntaxException, InterruptedException, + ExecutionException { + + Future f = IntentManager.submit(Intent.forUri( + new URI("test://a/b/c/"))); + assertFalse(f.get()); + + MockServices.setServices(TestOpenUriHandler.class); + try { + assertFalse(TestOpenUriHandler.HANDLED); + Future res2 = IntentManager.submit(Intent.forUri( + new URI("test://a/b/c/"))); + assertTrue(res2.get()); + assertTrue(TestOpenUriHandler.HANDLED); + + Future res3 = IntentManager.submit(Intent.forUri( + new URI("other://x/y/z/"))); + assertFalse(res3.get()); + } finally { + MockServices.setServices(); + } + } + + @SuppressWarnings("PublicInnerClass") + public static class TestOpenUriHandler implements OpenUriHandler { + + @SuppressWarnings("PackageVisibleField") + static boolean HANDLED = false; + + @Override + public boolean open(URI uri) { + if ("test".equals(uri.getScheme())) { + HANDLED = true; + return true; + } else { + return false; + } + } + } +}