diff options
author | Snjezana Peco | 2016-07-15 17:50:01 +0000 |
---|---|---|
committer | Victor Rubezhny | 2016-08-11 17:11:25 +0000 |
commit | e8b15c416f126c29416fdee94c3413f3584bba34 (patch) | |
tree | 46d92da2b94e0bca7683c3cb792e00953b6e516b | |
parent | ca363be313f7b70208b5c5c8d5b891698de9f62f (diff) | |
download | webtools.sourceediting-e8b15c416f126c29416fdee94c3413f3584bba34.tar.gz webtools.sourceediting-e8b15c416f126c29416fdee94c3413f3584bba34.tar.xz webtools.sourceediting-e8b15c416f126c29416fdee94c3413f3584bba34.zip |
Bug 494110 - Support for JSON Schema Catalog
Change-Id: Ib63761cb3a6f97c13e54e224eabe1d2266b82a40
Signed-off-by: Snjezana Peco <snjeza.peco@gmail.com>
20 files changed, 1687 insertions, 46 deletions
diff --git a/bundles/org.eclipse.wst.json.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.json.core/META-INF/MANIFEST.MF index df42eda859..33e79afa8e 100644 --- a/bundles/org.eclipse.wst.json.core/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.wst.json.core/META-INF/MANIFEST.MF @@ -12,7 +12,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources, org.eclipse.wst.validation, org.eclipse.wst.common.uriresolver, - org.eclipse.json + org.eclipse.json, + org.eclipse.core.net Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.wst.json.core, @@ -20,11 +21,38 @@ Export-Package: org.eclipse.wst.json.core, org.eclipse.wst.json.core.contenttype, org.eclipse.wst.json.core.document, org.eclipse.wst.json.core.format, + org.eclipse.wst.json.core.internal, + org.eclipse.wst.json.core.internal.contenttype, + org.eclipse.wst.json.core.internal.document, + org.eclipse.wst.json.core.internal.download, + org.eclipse.wst.json.core.internal.encoding, + org.eclipse.wst.json.core.internal.format, + org.eclipse.wst.json.core.internal.modelhandler, org.eclipse.wst.json.core.internal.parser;x-friends:="org.eclipse.wst.json.core.tests", + org.eclipse.wst.json.core.internal.parser.regions, + org.eclipse.wst.json.core.internal.preferences, + org.eclipse.wst.json.core.internal.schema, + org.eclipse.wst.json.core.internal.schema.catalog, + org.eclipse.wst.json.core.internal.text, + org.eclipse.wst.json.core.internal.util, + org.eclipse.wst.json.core.internal.validation, + org.eclipse.wst.json.core.internal.validation.core, + org.eclipse.wst.json.core.internal.validation.eclipse, org.eclipse.wst.json.core.jsonpath, org.eclipse.wst.json.core.modelhandler, org.eclipse.wst.json.core.preferences, org.eclipse.wst.json.core.regions, + org.eclipse.wst.json.core.schema.catalog, org.eclipse.wst.json.core.text, org.eclipse.wst.json.core.util, org.eclipse.wst.json.core.validation +Import-Package: org.apache.http, + org.apache.http.client, + org.apache.http.util, + org.apache.http.client.config, + org.apache.http.client.methods, + org.apache.http.conn, + org.apache.http.entity, + org.apache.http.impl.client, + org.apache.http.conn.routing, + org.apache.http.protocol diff --git a/bundles/org.eclipse.wst.json.core/schemastore/catalog.json b/bundles/org.eclipse.wst.json.core/schemastore/catalog.json new file mode 100644 index 0000000000..b9026de3a8 --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/schemastore/catalog.json @@ -0,0 +1,488 @@ +{ + "$schema": "http://json.schemastore.org/schema-catalog", + + "version": 1.0, + "schemas": [ + { + "name": "babelrc.json", + "description": "Babel configuration file", + "fileMatch": [ ".babelrc" ], + "url": "http://json.schemastore.org/babelrc" + }, + { + "name": ".bootstraprc", + "description": "Webpack bootstrap-loader configuration file", + "fileMatch": [ ".bootstraprc" ], + "url": "http://json.schemastore.org/bootstraprc" + }, + { + "name": "bower.json", + "description": "Bower package description file", + "fileMatch": [ "bower.json", ".bower.json" ], + "url": "http://json.schemastore.org/bower" + }, + { + "name": ".bowerrc", + "description": "Bower configuration file", + "fileMatch": [ ".bowerrc" ], + "url": "http://json.schemastore.org/bowerrc" + }, + { + "name": "bundleconfig.json", + "description": "Schema for bundleconfig.json files", + "fileMatch": [ "bundleconfig.json" ], + "url": "http://json.schemastore.org/bundleconfig" + }, + { + "name": "Chrome Extension", + "description": "Google Chrome extension manifest file", + "url": "http://json.schemastore.org/chrome-manifest" + }, + { + "name": "chutzpah.json", + "description": "Chutzpah configuration file", + "fileMatch": [ "chutzpah.json" ], + "url": "http://json.schemastore.org/chutzpah" + }, + { + "name": "coffeelint.json", + "description": "CoffeeLint configuration file", + "fileMatch": [ "coffeelint.json" ], + "url": "http://json.schemastore.org/coffeelint" + }, + { + "name": "composer.json", + "description": "PHP Composer configuration file", + "fileMatch": [ "composer.json" ], + "url": "http://json.schemastore.org/composer" + }, + { + "name": "component.json", + "description": "Web component file", + "fileMatch": [ "component.json" ], + "url": "http://json.schemastore.org/component" + }, + { + "name": "config.json", + "description": "ASP.NET project config file", + "fileMatch": [ "config.json" ], + "url": "http://json.schemastore.org/config" + }, + { + "name": "contribute.json", + "description": "A JSON schema for open-source project contribution data by Mozilla", + "fileMatch": [ "contribute.json" ], + "url": "http://json.schemastore.org/contribute" + }, + { + "name": ".csscomb.json", + "description": "A JSON schema CSS Comb's configuration file", + "fileMatch": [ ".csscomb.json" ], + "url": "http://json.schemastore.org/csscomb" + }, + { + "name": ".csslintrc", + "description": "A JSON schema CSS Lint's configuration file", + "fileMatch": [ ".csslintrc" ], + "url": "http://json.schemastore.org/csslintrc" + }, + { + "name": "debugsettings.json", + "description": "A JSON schema for the ASP.NET DebugSettings.json files", + "fileMatch": [ "debugsettings.json" ], + "url": "http://json.schemastore.org/launchsettings" + }, + { + "name": "epr-manifest.json", + "description": "Entry Point Regulation manifest file", + "fileMatch": [ "epr-manifest.json" ], + "url": "http://json.schemastore.org/epr-manifest" + }, + { + "name": ".eslintrc", + "description": "JSON schema for ESLint configuration files", + "fileMatch": [ ".eslintrc", ".eslintrc.json" ], + "url": "http://json.schemastore.org/eslintrc" + }, + { + "name": "geojson.json", + "description": "GeoJSON format for representing geographic data.", + "url": "http://json.schemastore.org/geojson" + }, + { + "name": "global.json", + "description": "ASP.NET global configuration file", + "fileMatch": [ "global.json" ], + "url": "http://json.schemastore.org/global" + }, + { + "name": "Grunt copy task", + "description": "Grunt copy task configuration file", + "fileMatch": [ "copy.json" ], + "url": "http://json.schemastore.org/grunt-copy-task" + }, + { + "name": "Grunt clean task", + "description": "Grunt clean task configuration file", + "fileMatch": [ "clean.json" ], + "url": "http://json.schemastore.org/grunt-clean-task" + }, + { + "name": "Grunt cssmin task", + "description": "Grunt cssmin task configuration file", + "fileMatch": [ "cssmin.json" ], + "url": "http://json.schemastore.org/grunt-cssmin-task" + }, + { + "name": "Grunt JSHint task", + "description": "Grunt JSHint task configuration file", + "fileMatch": [ "jshint.json" ], + "url": "http://json.schemastore.org/grunt-jshint-task" + }, + { + "name": "Grunt Watch task", + "description": "Grunt Watch task configuration file", + "fileMatch": [ "watch.json" ], + "url": "http://json.schemastore.org/grunt-watch-task" + }, + { + "name": "Grunt base task", + "description": "Schema for standard Grunt tasks", + "fileMatch": [ "grunt/*.json", "*-tasks.json" ], + "url": "http://json.schemastore.org/grunt-task" + }, + { + "name": "haxelib.json", + "description": "Haxelib manifest", + "fileMatch": [ "haxelib.json" ], + "url": "http://json.schemastore.org/haxelib" + }, + { + "name": "host-meta.json", + "description": "Schema for host-meta JDR files", + "fileMatch": [ "host-meta.json" ], + "url": "http://json.schemastore.org/host-meta" + }, + { + "name": ".htmlhintrc", + "description": "HTML Hint configuration file", + "fileMatch": [ ".htmlhintrc" ], + "url": "http://json.schemastore.org/htmlhint" + }, + { + "name": ".jsbeautifyrc", + "description": "js-beautify configuration file", + "fileMatch": [ ".jsbeautifyrc" ], + "url": "http://json.schemastore.org/jsbeautifyrc" + }, + { + "name": ".jscsrc", + "description": "JSCS configuration file", + "fileMatch": [ ".jscsrc", "jscsrc.json" ], + "url": "http://json.schemastore.org/jscsrc" + }, + { + "name": ".jshintrc", + "description": "JSHint configuration file", + "fileMatch": [ ".jshintrc" ], + "url": "http://json.schemastore.org/jshintrc" + }, + { + "name": ".jsinspectrc", + "description": "JSInspect configuration file", + "fileMatch": [ ".jsinspectrc" ], + "url": "http://json.schemastore.org/jsinspectrc" + }, + { + "name": "*.jsonld", + "description": "JSON Linked Data files", + "fileMatch": [ "*.jsonld" ], + "url": "http://json.schemastore.org/jsonld" + }, + { + "name": "JSONPatch", + "description": "JSONPatch files", + "fileMatch": [ "*.patch" ], + "url": "http://json.schemastore.org/json-patch" + }, + { + "name": "jsconfig.json", + "description": "JavaScript project configuration file", + "fileMatch": [ "jsconfig.json" ], + "url": "http://json.schemastore.org/jsconfig" + }, + { + "name": "launchsettings.json", + "description": "A JSON schema for the ASP.NET LaunchSettings.json files", + "fileMatch": [ "launchsettings.json" ], + "url": "http://json.schemastore.org/launchsettings" + }, + { + "name": "Microsoft Band Web Tile", + "description": "Microsoft Band Web Tile manifest file", + "url": "http://json.schemastore.org/band-manifest" + }, + { + "name": ".modernizrrc", + "description": "Webpack modernizr-loader configuration file", + "fileMatch": [ ".modernizrrc" ], + "url": "http://json.schemastore.org/modernizrrc" + }, + { + "name": "mycode.json", + "description": "JSON schema for mycode.js files", + "fileMatch": [ "mycode.json" ], + "url": "http://json.schemastore.org/mycode" + }, + { + "name": "news in JSON", + "description": "A JSON Schema for ninjs by the IPTC. News and publishing information. See http://dev.iptc.org/ninjs", + "fileMatch": [ "ninjs.json" ], + "url": "http://json.schemastore.org/ninjs" + }, + { + "name": "nuget-project.json", + "description": "JSON schema for NuGet project.json files.", + "url": "http://json.schemastore.org/nuget-project", + "versions": { + "3.3.0": "http://json.schemastore.org/nuget-project-3.3.0" + } + }, + { + "name": "package.json", + "description": "NPM configuration file", + "fileMatch": [ "package.json" ], + "url": "http://json.schemastore.org/package" + }, + { + "name": "package.manifest", + "description": "Umbraco package configuration file", + "fileMatch": [ "package.manifest" ], + "url": "http://json.schemastore.org/package.manifest" + }, + { + "name": "pattern.json", + "description": "Patternplate pattern manifest file", + "fileMatch": [ "pattern.json" ], + "url": "http://json.schemastore.org/pattern" + }, + { + "name": "project.json", + "description": "ASP.NET vNext project configuration file", + "fileMatch": [ "project.json" ], + "url": "http://json.schemastore.org/project", + "versions": { + "1.0.0-beta3": "http://json.schemastore.org/project-1.0.0-beta3", + "1.0.0-beta4": "http://json.schemastore.org/project-1.0.0-beta4", + "1.0.0-beta5": "http://json.schemastore.org/project-1.0.0-beta5", + "1.0.0-beta6": "http://json.schemastore.org/project-1.0.0-beta6", + "1.0.0-beta8": "http://json.schemastore.org/project-1.0.0-beta8", + "1.0.0-rc1": "http://json.schemastore.org/project-1.0.0-rc1", + "1.0.0-rc1-update1": "http://json.schemastore.org/project-1.0.0-rc1", + "1.0.0-rc2": "http://json.schemastore.org/project-1.0.0-rc2" + } + }, + { + "name": "project-1.0.0-beta3.json", + "description": "ASP.NET vNext project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-beta3" + }, + { + "name": "project-1.0.0-beta4.json", + "description": "ASP.NET vNext project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-beta4" + }, + { + "name": "project-1.0.0-beta5.json", + "description": "ASP.NET vNext project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-beta5" + }, + { + "name": "project-1.0.0-beta6.json", + "description": "ASP.NET vNext project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-beta6" + }, + { + "name": "project-1.0.0-beta8.json", + "description": "ASP.NET vNext project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-beta8" + }, + { + "name": "project-1.0.0-rc1.json", + "description": "ASP.NET vNext project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-rc1" + }, + { + "name": "project-1.0.0-rc2.json", + "description": ".NET Core project configuration file", + "url": "http://json.schemastore.org/project-1.0.0-rc2" + }, + { + "name": "*.resjson", + "description": "Windows App localization file", + "fileMatch": [ "*.resjson" ], + "url": "http://json.schemastore.org/resjson" + }, + { + "name": "JSON Resume", + "description": "A JSON format to describe resumes", + "fileMatch": [ "resume.json" ], + "url": "http://json.schemastore.org/resume" + }, + { + "name": "sarif-1.0.0.json", + "description": "Static Analysis Results Interchange Format (SARIF)", + "fileMatch": [ "*.sarif,*.sarif.json" ], + "url": "http://json.schemastore.org/sarif", + "versions": { + "1.0.0-beta.4": "http://json.schemastore.org/sarif-1.0.0-beta.4.json", + "1.0.0-beta.5": "http://json.schemastore.org/sarif-1.0.0-beta.5.json", + "1.0.0": "http://json.schemastore.org/sarif-1.0.0" + } + }, + { + "name": "sarif-1.0.0.json", + "description": "Static Analysis Results Interchange Format (SARIF)", + "url": "http://json.schemastore.org/sarif-1.0.0.json" + }, + { + "name": "sarif-1.0.0-beta.5.json", + "description": "Static Analysis Results Interchange Format (SARIF)", + "url": "http://json.schemastore.org/sarif-1.0.0-beta.5.json" + }, + { + "name": "sarif-1.0.0-beta.4.json", + "description": "Static Analysis Results Interchange Format (SARIF)", + "url": "http://json.schemastore.org/sarif-1.0.0-beta.4.json" + }, + { + "name": "Schema Catalog", + "description": "JSON Schema catalog files compatible with SchemaStore.org", + "url": "http://json.schemastore.org/schema-catalog" + }, + { + "name": "settings.job", + "description": "Azure Webjob settings file", + "fileMatch": [ "settings.job" ], + "url": "http://json.schemastore.org/settings.job" + }, + { + "name": "Source Maps v3", + "description": "Source Map files version 3", + "fileMatch": [ "*.map" ], + "url": "http://json.schemastore.org/sourcemap-v3" + }, + { + "name": ".sprite files", + "description": "Schema for image sprite generation files", + "fileMatch": [ "*.sprite" ], + "url": "http://json.schemastore.org/sprite" + }, + { + "name": "StyleCop Analyzers Configuration", + "description": "Configuration file for StyleCop Analyzers", + "fileMatch": [ "stylecop.json" ], + "url": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json" + }, + { + "name": "Swagger API 2.0", + "description": "Swagger API 2.0 schema", + "url": "http://json.schemastore.org/swagger-2.0" + }, + + { + "name": "templatsources.json", + "description": "SideWaffle template source schema", + "fileMatch": [ "templatesources.json" ], + "url": "http://json.schemastore.org/templatesources" + }, + { + "name": "tsconfig.json", + "description": "TypeScript compiler configuration file", + "fileMatch": [ "tsconfig.json" ], + "url": "http://json.schemastore.org/tsconfig" + }, + { + "name": "tsd.json", + "description": "JSON schema for DefinatelyTyped description manager (TSD)", + "fileMatch": [ "tsd.json" ], + "url": "http://json.schemastore.org/tsd" + }, + { + "name": "tsdrc.json", + "description": "TypeScript Definition manager (tsd) global settings file", + "fileMatch": [ ".tsdrc" ], + "url": "http://json.schemastore.org/tsdrc" + }, + { + "name": "tslint.json", + "description": "TypeScript Lint configuration file", + "fileMatch": [ "tslint.json" ], + "url": "http://json.schemastore.org/tslint" + }, + { + "name": "typings.json", + "description": "Typings TypeScript definitions manager definition file", + "fileMatch": [ "typings.json" ], + "url": "http://json.schemastore.org/typings" + }, + { + "name": "typingsrc.json", + "description": "Typings TypeScript definitions manager configuration file", + "fileMatch": [ ".typingsrc" ], + "url": "http://json.schemastore.org/typingsrc" + }, + { + "name": "vega.json", + "description": "Vega visualization specification file", + "fileMatch": [ "*.vg", "*.vg.json" ], + "url": "http://json.schemastore.org/vega" + }, + { + "name": "vega-lite.json", + "description": "Vega-Lite visualization specification file", + "fileMatch": [ "*.vl", "*.vl.json" ], + "url": "http://json.schemastore.org/vega-lite" + }, + { + "name": "version.json", + "description": "A project version descriptor file used by Nerdbank.GitVersioning", + "fileMatch": [ "version.json" ], + "url": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json" + }, + { + "name": "Web Manifest", + "description": "Web Appliation manifest file", + "fileMatch": [ "manifest.json" ], + "url": "http://json.schemastore.org/web-manifest" + }, + { + "name": "webjobs-list.json", + "description": "Azure Webjob list file", + "fileMatch": [ "webjobs-list.json" ], + "url": "http://json.schemastore.org/webjobs-list" + }, + { + "name": "webjobpublishsettings.json", + "description": "Azure Webjobs publish settings file", + "fileMatch": [ "webjobpublishsettings.json" ], + "url": "http://json.schemastore.org/webjob-publish-settings" + }, + { + "name": "JSON-stat 2.0", + "description": "JSON-stat 2.0 Schema", + "url": "https://json-stat.org/format/schema/2.0/" + }, + { + "name": "KSP-CKAN 1.16", + "description": "Metadata spec v1.16 for KSP-CKAN", + "fileMatch": [ "*.ckan" ], + "url": "http://json.schemastore.org/ksp-ckan-1.16" + }, + { + "name": "JSON Schema Draft 4", + "description": "Meta-validation schema for JSON Schema Draft 4", + "url": "http://json-schema.org/draft-04/schema" + } + ] +} diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/download/HttpClientProvider.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/download/HttpClientProvider.java new file mode 100644 index 0000000000..f84426885f --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/download/HttpClientProvider.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.eclipse.wst.json.core.internal.download; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Date; + +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.config.RequestConfig.Builder; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.net.proxy.IProxyService; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.json.internal.JSONPlugin; +import org.eclipse.wst.json.core.JSONCorePlugin; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +public class HttpClientProvider { + + private static final String JSON_DOWNLOAD_FOLDER = ".jsonDownloadFolder"; //$NON-NLS-1$ + public static final String PROTOCOL_FILE = "file"; //$NON-NLS-1$ + public static final String PROTOCOL_PLATFORM = "platform"; //$NON-NLS-1$ + + public static File getFile(URL url) throws IOException { + if (url == null) { + return null; + } + if (PROTOCOL_FILE.equals(url.getProtocol()) + || PROTOCOL_PLATFORM.equalsIgnoreCase(url.getProtocol())) { + File file; + try { + file = new File(new URI(url.toExternalForm())); + } catch (Exception e) { + file = new File(url.getFile()); + } + if (!file.exists()) { + return null; + } + return file; + } + File file = getCachedFile(url); + long urlLastModified = getLastModified(url); + if (file.exists()) { + long lastModified = file.lastModified(); + if (urlLastModified > lastModified) { + file = download(file, url); + file.setLastModified(urlLastModified); + } + } else { + file = download(file, url); + if (urlLastModified > -1) { + file.setLastModified(urlLastModified); + } + } + return file; + } + + private static File download(File file, URL url) { + CloseableHttpClient httpclient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + OutputStream out = null; + file.getParentFile().mkdirs(); + try { + HttpHost target = new HttpHost(url.getHost(), url.getPort(), url.getProtocol()); + Builder builder = RequestConfig.custom(); + HttpHost proxy = getProxy(target); + if (proxy != null) { + builder = builder.setProxy(proxy); + } + RequestConfig config = builder.build(); + HttpGet request = new HttpGet(url.toURI()); + request.setConfig(config); + response = httpclient.execute(target, request); + InputStream in = response.getEntity().getContent(); + out = new BufferedOutputStream(new FileOutputStream(file)); + copy(in, out); + return file; + } catch (Exception e) { + logWarning(e); + ; + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + } + } + if (response != null) { + try { + response.close(); + } catch (IOException e) { + } + } + try { + httpclient.close(); + } catch (IOException e) { + } + } + return null; + } + + private static void copy(InputStream in, OutputStream out) throws IOException { + byte[] buffer = new byte[8192]; + int n = 0; + while ((n = in.read(buffer)) != -1) { + out.write(buffer, 0, n); + } + } + + private static long getLastModified(URL url) { + CloseableHttpClient httpclient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + try { + HttpHost target = new HttpHost(url.getHost(), url.getPort(), url.getProtocol()); + Builder builder = RequestConfig.custom(); + HttpHost proxy = getProxy(target); + if (proxy != null) { + builder = builder.setProxy(proxy); + } + RequestConfig config = builder.build(); + HttpHead request = new HttpHead(url.toURI()); + request.setConfig(config); + response = httpclient.execute(target, request); + Header[] s = response.getHeaders("last-modified"); + if (s != null && s.length > 0) { + String lastModified = s[0].getValue(); + return new Date(lastModified).getTime(); + } + } catch (Exception e) { + logWarning(e); + return -1; + } finally { + if (response != null) { + try { + response.close(); + } catch (IOException e) { + } + } + try { + httpclient.close(); + } catch (IOException e) { + } + } + return -1; + } + + private static HttpHost getProxy(HttpHost target) { + final IProxyService proxyService = getProxyService(); + IProxyData[] select = null; + try { + select = proxyService.select(new URI(target.toURI())); + } catch (URISyntaxException e) { + logWarning(e); + return null; + } + String type = target.getSchemeName(); + for (IProxyData proxyData : select) { + if (proxyData.getType().equals(type)) { + return new HttpHost(proxyData.getHost(), proxyData.getPort()); + } + } + return null; + } + + private static void logWarning(Exception e) { + IStatus status = new Status(IStatus.WARNING, JSONCorePlugin.PLUGIN_ID, e.getMessage(), e); + JSONCorePlugin.getDefault().getLog().log(status); + } + + public static IProxyService getProxyService() { + BundleContext bc = JSONPlugin.getDefault().getBundle().getBundleContext(); + ServiceReference<?> serviceReference = bc.getServiceReference(IProxyService.class.getName()); + IProxyService service = (IProxyService) bc.getService(serviceReference); + return service; + } + + private static File getCachedFile(URL url) { + IPath stateLocation = JSONCorePlugin.getDefault().getStateLocation(); + IPath downloadFolder = stateLocation.append(JSON_DOWNLOAD_FOLDER); + String urlPath = url.getPath(); + IPath filePath = downloadFolder.append(urlPath); + File file = filePath.toFile(); + return file; + } + +} diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/Catalog.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/Catalog.java index 16acdcd0d0..e7cc896ad9 100644 --- a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/Catalog.java +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/Catalog.java @@ -11,7 +11,6 @@ package org.eclipse.wst.json.core.internal.schema.catalog; import java.io.IOException; -import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -287,6 +286,7 @@ public class Catalog implements ICatalog { public void load() { new CatalogContributorRegistryReader(Catalog.this).readRegistry(); + new CatalogSchemastoreReader(Catalog.this).readSchemastore(); /* * Here we save the file in order to 'reflect' the catalog that * we've created from plugin extensions to disk. The 'system' @@ -298,34 +298,9 @@ public class Catalog implements ICatalog { class UserCatalogLS extends CatalogLS { public void load() { - InputStream inputStream = null; - try { - if (location != null && location.length() > 0) { - URL url = new URL(location); - inputStream = url.openStream(); - boolean oldNotificationEnabled = isNotificationEnabled(); - setNotificationEnabled(false); - clear(); - try { - // CatalogReader.read(Catalog.this, inputStream); - } finally { - setNotificationEnabled(oldNotificationEnabled); - } - } else { - clear(); - } - notifyChanged(); - } catch (Exception e) { - // This is OK since the catalog may not exist before we create - // it - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (Exception e) { - } - } - } + new CatalogUserCatalogReader(Catalog.this).readCatalog(); + + save(); } } @@ -369,7 +344,11 @@ public class Catalog implements ICatalog { public void addCatalogElement(ICatalogElement element) { synchronized (catalogElements) { - catalogElements.add(element); + if (!catalogElements.contains(element)) { + catalogElements.add(element); + } else { + return; + } } element.setOwnerCatalog(this); internalResolver = null; diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogElement.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogElement.java index 9f19681e92..73598b2ed7 100644 --- a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogElement.java +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogElement.java @@ -146,4 +146,29 @@ public class CatalogElement implements ICatalogElement { return element; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CatalogElement other = (CatalogElement) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + } diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogSchemastoreReader.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogSchemastoreReader.java new file mode 100644 index 0000000000..5a323d7c8d --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogSchemastoreReader.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.eclipse.wst.json.core.internal.schema.catalog; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Iterator; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.json.provisonnal.com.eclipsesource.json.JsonArray; +import org.eclipse.json.provisonnal.com.eclipsesource.json.JsonObject; +import org.eclipse.json.provisonnal.com.eclipsesource.json.JsonValue; +import org.eclipse.wst.json.core.JSONCorePlugin; +import org.eclipse.wst.json.core.internal.Logger; +import org.eclipse.wst.json.core.internal.download.HttpClientProvider; +import org.eclipse.wst.json.core.schema.catalog.ICatalog; +import org.eclipse.wst.json.core.schema.catalog.ICatalogElement; +import org.eclipse.wst.json.core.schema.catalog.ICatalogEntry; +import org.osgi.framework.Bundle; + +public class CatalogSchemastoreReader { + + private static final String SCHEMAS = "schemas"; //$NON-NLS-1$ + private static final String SCHEMASTORE_CATALOG = "https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/api/json/catalog.json"; //$NON-NLS-1$ + protected ICatalog catalog; + + protected CatalogSchemastoreReader(ICatalog catalog) { + this.catalog = catalog; + } + + protected void readSchemastore() { + File f = getUrl(); + if (f != null) { + int type = ICatalogEntry.ENTRY_TYPE_SCHEMA; + JsonValue schemas; + try { + InputStreamReader reader = new InputStreamReader(new FileInputStream(f)); + JsonObject json = JsonObject.readFrom(reader); + schemas = json.get(SCHEMAS); + } catch (IOException e) { + Logger.logException(e); + return; + } + if (schemas != null && schemas instanceof JsonArray) { + JsonArray elements = (JsonArray) schemas; + Iterator<JsonValue> iter = elements.iterator(); + while (iter.hasNext()) { + JsonValue value = iter.next(); + if (value instanceof JsonObject) { + JsonObject jsonObject = (JsonObject) value; + JsonValue urlJson = jsonObject.get("url"); //$NON-NLS-1$ + JsonValue fileMatchJson = jsonObject.get("fileMatch"); //$NON-NLS-1$ + if (urlJson != null && fileMatchJson != null && urlJson.isString() && fileMatchJson.isArray()) { + String url = urlJson.asString(); + JsonArray fileMatchArray = fileMatchJson.asArray(); + Iterator<JsonValue> fileIter = fileMatchArray.iterator(); + while (fileIter.hasNext()) { + JsonValue fileMatchValue = fileIter.next(); + if (fileMatchValue.isString()) { + String fileMatch = fileMatchValue.asString(); + ICatalogElement catalogElement = catalog.createCatalogElement(type); + if (catalogElement instanceof ICatalogEntry) { + ICatalogEntry entry = (ICatalogEntry) catalogElement; + entry.setKey(fileMatch); + entry.setURI(url); + entry.setId(fileMatch); + } + catalog.addCatalogElement(catalogElement); + } + } + } + } + } + } + } + } + + private static File getUrl() { + try { + File f = HttpClientProvider.getFile(new URL(SCHEMASTORE_CATALOG)); + if (f == null || !f.exists()) { + URL url = getUrlFromBundle(); + File file; + try { + file = new File(url.toURI()); + } catch(URISyntaxException e) { + file = new File(url.getPath()); + } + return file; + } else { + return f; + } + } catch (Exception e) { + Logger.logException(e); + } + return null; + } + + private static URL getUrlFromBundle() { + Bundle bundle = Platform.getBundle(JSONCorePlugin.PLUGIN_ID); + if (bundle != null) { + URL[] urls = FileLocator.findEntries(bundle, new Path("/schemastore/catalog.json")); //$NON-NLS-1$ + if (urls != null && urls.length > 0) { + try { + return FileLocator.resolve(urls[0]); + } catch (IOException e) { + Logger.logException(e); + } + } + } + return null; + } + +} diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogUserCatalogReader.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogUserCatalogReader.java new file mode 100644 index 0000000000..0ca05c1e54 --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/CatalogUserCatalogReader.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.eclipse.wst.json.core.internal.schema.catalog; + +import java.util.Set; + +import org.eclipse.wst.json.core.schema.catalog.ICatalog; +import org.eclipse.wst.json.core.schema.catalog.ICatalogElement; +import org.eclipse.wst.json.core.schema.catalog.ICatalogEntry; + +public class CatalogUserCatalogReader { + + protected ICatalog catalog; + + protected CatalogUserCatalogReader(ICatalog catalog) { + this.catalog = catalog; + } + + protected void readCatalog() { + int type = ICatalogEntry.ENTRY_TYPE_SCHEMA; + Set<UserEntry> entries = EntryParser.getUserEntries(); + for (UserEntry ue : entries) { + ICatalogElement catalogElement = catalog.createCatalogElement(type); + if (catalogElement instanceof ICatalogEntry) { + ICatalogEntry entry = (ICatalogEntry) catalogElement; + entry.setKey(ue.getFileMatch()); + entry.setURI(ue.getUrl().toString()); + entry.setId(ue.getFileMatch()); + } + catalog.addCatalogElement(catalogElement); + } + } + +} diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/EntryParser.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/EntryParser.java new file mode 100644 index 0000000000..acb659aae8 --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/EntryParser.java @@ -0,0 +1,138 @@ +/************************************************************************************* + * Copyright (c) 2014-2015 Red Hat, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * JBoss by Red Hat - Initial implementation. + ************************************************************************************/ +package org.eclipse.wst.json.core.internal.schema.catalog; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.wst.json.core.JSONCorePlugin; + +@SuppressWarnings("nls") +public class EntryParser { + + public static final String JSON_CATALOG_ENTRIES = "catalogEntries"; //$NON-NLS-1$ + private static final JAXBContext jaxbContext; + + static { + try { + jaxbContext = JAXBContext.newInstance(EntriesWrapper.class); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + public Set<UserEntry> parse(String xml) throws CoreException { + if (xml == null || xml.trim().isEmpty()) { + return null; + } + try { + EntriesWrapper list = (EntriesWrapper) unmarshall(jaxbContext, xml); + return list.entries == null ? Collections.<UserEntry>emptySet() : list.entries; + } catch (Exception e) { + throw new CoreException(new Status(IStatus.ERROR, JSONCorePlugin.PLUGIN_ID, + "Unable to parse entry", e)); + } + } + + public String serialize(Set<UserEntry> entries) throws CoreException { + try { + EntriesWrapper list = new EntriesWrapper(); + list.entries = entries; + Marshaller marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + StringWriter writer = new StringWriter(); + marshaller.marshal(list, writer); + return writer.toString(); + } catch (Exception shouldntHappen) { + throw new CoreException(new Status(IStatus.ERROR, JSONCorePlugin.PLUGIN_ID, + "Unable to serialize entries ", shouldntHappen)); + } + } + + public static Set<UserEntry> getUserEntries() { + Set<UserEntry> entries = new LinkedHashSet<UserEntry>(); + IEclipsePreferences prefs = getPreferences(); + String xml = prefs.get(JSON_CATALOG_ENTRIES, null); + if (xml != null && !xml.trim().isEmpty()) { + try { + Set<UserEntry> set = new EntryParser().parse(xml); + if (set != null) { + entries.addAll(set); + } + } catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, JSONCorePlugin.PLUGIN_ID, e + .getLocalizedMessage(), e); + JSONCorePlugin.getDefault().getLog().log(status); + } + } + return entries; + } + + private static IEclipsePreferences getPreferences() { + IEclipsePreferences preferences = InstanceScope.INSTANCE + .getNode("org.eclipse.wst.json.ui"); //$NON-NLS-1$ + return preferences; + } + + @XmlRootElement(name = "entries") + @XmlAccessorType (XmlAccessType.FIELD) + static class EntriesWrapper { + @XmlElement(name = "entry", type=UserEntry.class) + Set<UserEntry> entries; + } + + protected Object unmarshall(JAXBContext jaxbContext, String xml) throws JAXBException, IOException, XMLStreamException { + return unmarshall(jaxbContext, new StringReader(xml)); + } + + protected Object unmarshall(JAXBContext jaxbContext, File file) throws JAXBException, IOException, XMLStreamException { + return unmarshall(jaxbContext, new FileReader(file)); + } + + protected Object unmarshall(JAXBContext jaxbContext, Reader reader) throws JAXBException, IOException, XMLStreamException { + Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + XMLInputFactory xmlif = XMLInputFactory.newInstance(); + Reader r = null; + try { + r = reader; + XMLStreamReader xmler = xmlif.createXMLStreamReader(r); + return jaxbUnmarshaller.unmarshal(xmler); + } finally { + if (r != null) { + r.close(); + } + } + } +} diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/UserEntries.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/UserEntries.java new file mode 100644 index 0000000000..23b296850f --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/UserEntries.java @@ -0,0 +1,26 @@ +/************************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * JBoss by Red Hat - Initial implementation. + ************************************************************************************/ +package org.eclipse.wst.json.core.internal.schema.catalog; + +import java.util.HashSet; +import java.util.Set; + +public class UserEntries { + private Set<UserEntry> entries = new HashSet<UserEntry>(); + + public Set<UserEntry> getEntries() { + return entries; + } + + public void add(UserEntry entry) { + entries.add(entry); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/UserEntry.java b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/UserEntry.java new file mode 100644 index 0000000000..512fa9cbbc --- /dev/null +++ b/bundles/org.eclipse.wst.json.core/src/org/eclipse/wst/json/core/internal/schema/catalog/UserEntry.java @@ -0,0 +1,45 @@ +/************************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * JBoss by Red Hat - Initial implementation. + ************************************************************************************/ +package org.eclipse.wst.json.core.internal.schema.catalog; + +import java.net.URI; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlAccessorType (XmlAccessType.FIELD) +@XmlRootElement(name="entry") +public class UserEntry { + + @XmlAttribute + private String fileMatch; + + @XmlAttribute + private URI url; + + public String getFileMatch() { + return fileMatch; + } + + public void setFileMatch(String fileMatch) { + this.fileMatch = fileMatch; + } + + public URI getUrl() { + return url; + } + + public void setUrl(URI url) { + this.url = url; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.json.schemaprocessor/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.json.schemaprocessor/META-INF/MANIFEST.MF index b534b58a7a..1f92e91161 100644 --- a/bundles/org.eclipse.wst.json.schemaprocessor/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.wst.json.schemaprocessor/META-INF/MANIFEST.MF @@ -15,4 +15,6 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.json Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy +Export-Package: org.eclipse.wst.json.schemaprocessor, + org.eclipse.wst.json.schemaprocessor.internal diff --git a/bundles/org.eclipse.wst.json.schemaprocessor/src/org/eclipse/wst/json/schemaprocessor/internal/JSONSchemaProcessor.java b/bundles/org.eclipse.wst.json.schemaprocessor/src/org/eclipse/wst/json/schemaprocessor/internal/JSONSchemaProcessor.java index d330918278..f5eda6c734 100644 --- a/bundles/org.eclipse.wst.json.schemaprocessor/src/org/eclipse/wst/json/schemaprocessor/internal/JSONSchemaProcessor.java +++ b/bundles/org.eclipse.wst.json.schemaprocessor/src/org/eclipse/wst/json/schemaprocessor/internal/JSONSchemaProcessor.java @@ -10,27 +10,43 @@ */
package org.eclipse.wst.json.schemaprocessor.internal;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
+import java.util.LinkedHashMap;
+import java.util.Map;
import org.eclipse.json.impl.schema.JSONSchemaDocument;
import org.eclipse.json.schema.IJSONSchemaDocument;
import org.eclipse.json.schema.IJSONSchemaProcessor;
-import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;
+import org.eclipse.wst.json.core.internal.download.HttpClientProvider;
public class JSONSchemaProcessor implements IJSONSchemaProcessor {
+ private static final int MAP_SIZE = 10;
+ private static Map<String,IJSONSchemaDocument> schemaDocuments = new LinkedHashMap<String, IJSONSchemaDocument>();
+
@Override
public IJSONSchemaDocument getSchema(String uriString) throws IOException {
- String physicalLocation = URIResolverPlugin.createResolver()
- .resolvePhysicalLocation("", "", uriString);
- URL url = new URL(physicalLocation);
- return new JSONSchemaDocument(new InputStreamReader(url.openStream()));
+ IJSONSchemaDocument schemaDocument = schemaDocuments.get(uriString);
+ if (schemaDocument != null) {
+ return schemaDocument;
+ }
+ int size = schemaDocuments.size();
+ if (size > MAP_SIZE) {
+ String key = schemaDocuments.keySet().iterator().next();
+ schemaDocuments.remove(key);
+ }
+ File f = HttpClientProvider.getFile(new URL(uriString));
+ schemaDocument = new JSONSchemaDocument(new InputStreamReader(new FileInputStream(f)));
+ schemaDocuments.put(uriString, schemaDocument);
+ return schemaDocument;
}
- // @Override
- // public IJSONProperty findProperty(IJSONPath path, IJSONSchema schema) {
- // // TODO Auto-generated method stub
- // return null;
- // }
+
+ public static void clearCache() {
+ schemaDocuments.clear();
+ }
+
}
diff --git a/bundles/org.eclipse.wst.json.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.json.ui/META-INF/MANIFEST.MF index dfce495a5a..ff37b5ef6f 100644 --- a/bundles/org.eclipse.wst.json.ui/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.wst.json.ui/META-INF/MANIFEST.MF @@ -17,7 +17,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.wst.json.core, org.eclipse.wst.validation, org.eclipse.ui.workbench.texteditor, - org.eclipse.json + org.eclipse.json, + org.eclipse.wst.json.schemaprocessor;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.wst.json.ui, diff --git a/bundles/org.eclipse.wst.json.ui/icons/WizBan.png b/bundles/org.eclipse.wst.json.ui/icons/WizBan.png Binary files differnew file mode 100644 index 0000000000..1173df9a4c --- /dev/null +++ b/bundles/org.eclipse.wst.json.ui/icons/WizBan.png diff --git a/bundles/org.eclipse.wst.json.ui/plugin.properties b/bundles/org.eclipse.wst.json.ui/plugin.properties index 22cb8113f9..8094e8c35a 100644 --- a/bundles/org.eclipse.wst.json.ui/plugin.properties +++ b/bundles/org.eclipse.wst.json.ui/plugin.properties @@ -26,6 +26,7 @@ JSON_Source.name=Editor JSON_Content_Assist.name=Content Assist JSON_Validator.name=Validation JSON_Templates.name=Templates +_UI_PREF_JSON_CATALOG=JSON Catalog JSON_Styles.name=Styles JSON_Syntax_Coloring=Syntax Coloring JSON_Typing=Typing @@ -41,3 +42,5 @@ proposalCategory.jsonTemplates=JSON Template Proposals All_JSON_context_type_Extension_Element.name=All JSON JSON_New_context_type_Extension_Element.name=New JSON JSON_Package_context_type_Extension_Element.name=New package.json + +preferenceKeywords.jsoncatalog=JSON Catalog diff --git a/bundles/org.eclipse.wst.json.ui/plugin.xml b/bundles/org.eclipse.wst.json.ui/plugin.xml index d59992a960..a1c188a62e 100644 --- a/bundles/org.eclipse.wst.json.ui/plugin.xml +++ b/bundles/org.eclipse.wst.json.ui/plugin.xml @@ -133,13 +133,14 @@ id="org.eclipse.wst.sse.ui.preferences.json.colors"> <keywordReference id="org.eclipse.wst.json.ui.styles"/> </page> - <!--<page + <page name="%_UI_PREF_JSON_CATALOG" category="org.eclipse.wst.json.ui.preferences.json" - class="org.eclipse.wst.json.ui.internal.catalog.JSONCatalogPreferencePage" - id="org.eclipse.wst.json.core.ui.JSONCatalogPreferencePage"> - <keywordReference id="org.eclipse.wst.json.ui.jsoncatalog"/> + class="org.eclipse.wst.json.ui.internal.preferences.JSONCatalogPreferencePage" + id="org.eclipse.wst.json.ui.internal.preferences.JSONCatalogPreferencePage"> + <keywordReference id="org.eclipse.wst.json.ui.jsoncatalog"/> </page> + <!-- <page name="%JSON_Typing" category="org.eclipse.wst.sse.ui.preferences.json.source" @@ -187,6 +188,9 @@ <keyword label="%preferenceKeywords.webcontent" id="org.eclipse.wst.json.ui.webcontent"/> + <keyword + label="%preferenceKeywords.jsoncatalog" + id="org.eclipse.wst.json.ui.jsoncatalog"/> <keyword id="org.eclipse.wst.json.ui.contentassist" label="%preferenceKeywords.contentassist"> diff --git a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.java b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.java index 48f22ab811..c8ab168ee7 100644 --- a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.java +++ b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.java @@ -23,6 +23,20 @@ public class JSONUIMessages extends NLS { private static final String BUNDLE_NAME = "org.eclipse.wst.json.ui.internal.JSONUIMessages";//$NON-NLS-1$
+ public static String Invalid_URL;
+ public static String The_name_field_is_required;
+ public static String The_entry_already_exists;
+ public static String The_url_field_is_required;
+ public static String Browse;
+ public static String URL;
+ public static String FileMatch;
+ public static String Add_Catalog_Entry;
+ public static String Edit_Catalog_Entry;
+ public static String Remove;
+ public static String Edit;
+ public static String Add;
+ public static String JSON_Catalog_Entries;
+
private static ResourceBundle fResourceBundle;
// Validation
diff --git a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.properties b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.properties index 28ad11ad37..f6ca05f6d3 100644 --- a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.properties +++ b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/JSONUIMessages.properties @@ -79,3 +79,18 @@ PrefsLabel_SelectorWhitespace=Inser&t whitespace between selectors ## JSON Preferences -- source ##
PrefsLabel_WrappingWithoutAttr=Disable wrapping in style &attribute of HTML
PrefsLabel_WrappingInsertLineBreak=Insert &line break between properties
+
+JSON_Catalog_Entries=JSON Catalog Entries
+Add=Add
+Edit=Edit
+Remove=Remove
+Add_Catalog_Entry=Add Catalog Entry
+Edit_Catalog_Entry=Edit Catalog Entry
+FileMatch=File Match:
+URL=URL:
+Browse=Browse...
+The_name_field_is_required=The name field is required.
+The_entry_already_exists=The entry already exists.
+The_url_field_is_required=The url field is required.
+Invalid_URL=Invalid url.
+
diff --git a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/preferences/EntryDialog.java b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/preferences/EntryDialog.java new file mode 100644 index 0000000000..beba9e746b --- /dev/null +++ b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/preferences/EntryDialog.java @@ -0,0 +1,213 @@ +/************************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * JBoss by Red Hat - Initial implementation. + ************************************************************************************/ +package org.eclipse.wst.json.ui.internal.preferences; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Set; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.wst.json.core.internal.schema.catalog.UserEntries; +import org.eclipse.wst.json.core.internal.schema.catalog.UserEntry; +import org.eclipse.wst.json.ui.internal.JSONUIMessages; +import org.eclipse.wst.json.ui.internal.JSONUIPlugin; + +public class EntryDialog extends TitleAreaDialog { + + private Image dlgTitleImage; + private UserEntry selectedEntry; + private String fileMatch; + private URI url; + private Text fileMatchText; + private Text urlText; + private Button okButton; + private UserEntries entries; + + protected EntryDialog(Shell parentShell, UserEntry entry, UserEntries entries) { + super(parentShell); + this.selectedEntry = entry; + this.entries = entries; + } + + @Override + protected Control createContents(Composite parent) { + + Control contents = super.createContents(parent); + if (selectedEntry == null) { + setTitle(JSONUIMessages.Add_Catalog_Entry); + setMessage(JSONUIMessages.Add_Catalog_Entry); + } else { + setTitle(JSONUIMessages.Edit_Catalog_Entry); + setMessage(JSONUIMessages.Edit_Catalog_Entry); + } + ImageDescriptor descriptor = JSONUIPlugin + .imageDescriptorFromPlugin(JSONUIPlugin.PLUGIN_ID, + "icons/WizBan.png"); //$NON-NLS-1$ + if(descriptor != null) { + dlgTitleImage = descriptor.createImage(); + setTitleImage(dlgTitleImage); + } + + return contents; + } + + @Override + public boolean close() { + if (dlgTitleImage != null) { + dlgTitleImage.dispose(); + } + return super.close(); + } + @Override + protected Control createDialogArea(Composite parent) { + Composite parentComposite = (Composite) super.createDialogArea(parent); + + Composite container = new Composite(parentComposite, SWT.FILL); + GridLayout layout = new GridLayout(3,false); + layout.marginWidth = layout.marginHeight = 10; + container.setLayout(layout); + GridData gd = new GridData(GridData.FILL_BOTH); + container.setLayoutData(gd); + + Label nameLabel = new Label(container, SWT.NONE); + nameLabel.setText(JSONUIMessages.FileMatch); + fileMatchText = new Text(container, SWT.SINGLE|SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan=2; + fileMatchText.setLayoutData(gd); + fileMatchText.addModifyListener(new ModifyListener(){ + + public void modifyText(ModifyEvent e) { + validatePage(); + } + }); + + Label urlLabel = new Label(container, SWT.NONE); + urlLabel.setText(JSONUIMessages.URL); + urlText = new Text(container, SWT.SINGLE|SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + urlText.setLayoutData(gd); + urlText.addModifyListener(new ModifyListener(){ + + public void modifyText(ModifyEvent e) { + validatePage(); + } + + }); + if (selectedEntry != null) { + urlText.setText(selectedEntry.getUrl().toString()); + fileMatchText.setText(selectedEntry.getFileMatch()); + } + Button browse = new Button(container,SWT.PUSH); + browse.setText(JSONUIMessages.Browse); + browse.addSelectionListener(new SelectionListener(){ + + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(getShell(), SWT.SINGLE); + String result = dialog.open(); + if (result == null || result.trim().length() == 0) { + return; + } + try { + String urlString = new File(result).toURI().toURL().toString(); + urlText.setText(urlString); + } catch (MalformedURLException e1) { + urlText.setText("file:///" + result); //$NON-NLS-1$ + } + } + public void widgetDefaultSelected(SelectionEvent e) { + + } + }); + + return parentComposite; + } + + private boolean validatePage() { + fileMatch = null; + url = null; + if (fileMatchText.getText().trim().length() <= 0) { + setErrorMessage(JSONUIMessages.The_name_field_is_required); + return updateButton(false); + } + Set<UserEntry> list = entries.getEntries(); + for(UserEntry entry:list) { + if (entry != selectedEntry && fileMatchText.getText().equals(entry.getFileMatch())) { + setErrorMessage(JSONUIMessages.The_entry_already_exists); + return updateButton(false); + } + } + if (urlText.getText().trim().length() <= 0) { + setErrorMessage(JSONUIMessages.The_url_field_is_required); + return updateButton(false); + } + try { + @SuppressWarnings("unused") + URL url = new URL(urlText.getText()); + } catch (MalformedURLException e) { + setErrorMessage(JSONUIMessages.Invalid_URL); + return updateButton(false); + } + setErrorMessage(null); + fileMatch = fileMatchText.getText(); + try { + url = new URL(urlText.getText()).toURI(); + } catch (MalformedURLException ignore) { + } catch (URISyntaxException ignore) { + } + return updateButton(true); + } + + private boolean updateButton(boolean enabled) { + if (okButton != null) { + okButton.setEnabled(enabled); + } + return false; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, + IDialogConstants.OK_LABEL, true); + okButton.setEnabled(selectedEntry != null); + createButton(parent, IDialogConstants.CANCEL_ID, + IDialogConstants.CANCEL_LABEL, false); + } + + public String getFileMatch() { + return fileMatch; + } + + public URI getURL() { + return url; + } + +} diff --git a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/preferences/JSONCatalogPreferencePage.java b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/preferences/JSONCatalogPreferencePage.java new file mode 100644 index 0000000000..24fc4a8eca --- /dev/null +++ b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/preferences/JSONCatalogPreferencePage.java @@ -0,0 +1,263 @@ +/************************************************************************************* + * Copyright (c) 2016 Red Hat, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * JBoss by Red Hat - Initial implementation. + ************************************************************************************/ +package org.eclipse.wst.json.ui.internal.preferences; + +import java.net.URI; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.ITreeSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.wst.json.core.JSONCorePlugin; +import org.eclipse.wst.json.core.internal.schema.catalog.EntryParser; +import org.eclipse.wst.json.core.internal.schema.catalog.UserEntries; +import org.eclipse.wst.json.core.internal.schema.catalog.UserEntry; +import org.eclipse.wst.json.schemaprocessor.internal.JSONSchemaProcessor; +import org.eclipse.wst.json.ui.internal.JSONUIMessages; +import org.eclipse.wst.json.ui.internal.JSONUIPlugin; + +public class JSONCatalogPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + + private TreeViewer viewer; + private UserEntries entries; + private UserEntry selectedEntry; + + public void init(IWorkbench workbench) { + } + + @Override + protected void performDefaults() { + storePreferences(); + super.performDefaults(); + } + + @Override + public boolean performOk() { + storePreferences(); + return super.performOk(); + } + + private void storePreferences() { + IEclipsePreferences prefs = getPreferences(); + try { + String value = new EntryParser().serialize(entries.getEntries()); + prefs.put(EntryParser.JSON_CATALOG_ENTRIES, value); + JSONCorePlugin.getDefault().clearCatalogCache(); + JSONSchemaProcessor.clearCache(); + } catch (Exception e) { + logException(e); + } + } + + private static IEclipsePreferences getPreferences() { + IEclipsePreferences preferences = InstanceScope.INSTANCE + .getNode("org.eclipse.wst.json.ui"); //$NON-NLS-1$ + return preferences; + } + + private static void logException(Exception e) { + IStatus status = new Status(IStatus.ERROR, JSONUIPlugin.PLUGIN_ID, e + .getLocalizedMessage(), e); + JSONUIPlugin.getDefault().getLog().log(status); + } + + @Override + protected Control createContents(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, false); + layout.marginWidth = 0; + layout.marginHeight = 0; + composite.setLayout(layout); + + Group entriesGroup = new Group(composite, SWT.NONE); + entriesGroup.setText(JSONUIMessages.JSON_Catalog_Entries); + GridLayout gl = new GridLayout(2, false); + entriesGroup.setLayout(gl); + entriesGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + + viewer = new TreeViewer(entriesGroup, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); + viewer.setContentProvider(new EntriesContentProvider()); + viewer.setLabelProvider(new EntriesLabelProvider()); + entries = new UserEntries(); + entries.getEntries().addAll(EntryParser.getUserEntries()); + viewer.setInput(entries); + viewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); + viewer.expandAll(); + + Composite buttonComposite = new Composite(entriesGroup, SWT.NONE); + buttonComposite.setLayout(new GridLayout(1, false)); + buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + + Button addButton = new Button(buttonComposite, SWT.PUSH); + addButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + addButton.setText(JSONUIMessages.Add); + addButton.addSelectionListener(new SelectionListener() { + + public void widgetDefaultSelected(SelectionEvent e) { + + } + + public void widgetSelected(SelectionEvent e) { + EntryDialog dialog = new EntryDialog(getShell(), null, entries); + int ok = dialog.open(); + if (ok == Window.OK) { + String fileMatch = dialog.getFileMatch(); + if (fileMatch != null) { + URI url = dialog.getURL(); + UserEntry entry = new UserEntry(); + entry.setUrl(url); + entry.setFileMatch(fileMatch); + entries.add(entry); + viewer.refresh(); + } + } + } + }); + final Button editButton = new Button(buttonComposite, SWT.PUSH); + editButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + editButton.setText(JSONUIMessages.Edit); + editButton.setEnabled(false); + editButton.addSelectionListener(new SelectionListener() { + + public void widgetSelected(SelectionEvent e) { + if (selectedEntry == null) { + return; + } + EntryDialog dialog = new EntryDialog(getShell(), selectedEntry, entries); + int ok = dialog.open(); + if (ok == Window.OK) { + String fileMatch = dialog.getFileMatch(); + if (fileMatch != null) { + URI url = dialog.getURL(); + UserEntry entry = selectedEntry; + entry.setUrl(url); + entry.setFileMatch(fileMatch); + viewer.refresh(); + } + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + + } + }); + final Button removeButton = new Button(buttonComposite, SWT.PUSH); + removeButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + removeButton.setText(JSONUIMessages.Remove); + removeButton.setEnabled(false); + + removeButton.addSelectionListener(new SelectionListener() { + + public void widgetSelected(SelectionEvent e) { + if (selectedEntry != null) { + entries.getEntries().remove(selectedEntry); + viewer.refresh(); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + + } + }); + + viewer.addSelectionChangedListener(new ISelectionChangedListener() { + + public void selectionChanged(SelectionChangedEvent event) { + editButton.setEnabled(false); + removeButton.setEnabled(false); + selectedEntry = null; + ISelection selection = event.getSelection(); + if (selection instanceof ITreeSelection) { + ITreeSelection treeSelection = (ITreeSelection) selection; + Object object = treeSelection.getFirstElement(); + if (object instanceof UserEntry) { + selectedEntry = (UserEntry) object; + editButton.setEnabled(true); + removeButton.setEnabled(true); + } + } + } + }); + + return composite; + } + + class EntriesContentProvider implements ITreeContentProvider { + + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof UserEntries) { + return ((UserEntries) parentElement).getEntries().toArray(); + } + return new Object[0]; + } + + public Object getParent(Object element) { + return null; + } + + public boolean hasChildren(Object element) { + return element instanceof UserEntries; + } + + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + } + + class EntriesLabelProvider extends LabelProvider { + + @Override + public Image getImage(Object element) { + return super.getImage(element); + } + + @Override + public String getText(Object element) { + if (element instanceof UserEntry) { + UserEntry entry = (UserEntry) element; + String result = entry.getFileMatch(); + return result; + } + return super.getText(element); + } + + } + +} |