Java tutorial
/* * Copyright (C) The Ambient Dynamix Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ambientdynamix.update.contextplugin; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.ambientdynamix.api.application.VersionInfo; import org.ambientdynamix.api.contextplugin.PluginConstants.PLATFORM; import org.ambientdynamix.util.RepositoryInfo; import org.ambientdynamix.util.Utils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; import android.util.Log; /** * IContextPluginConnector for accessing Context Plug-ins using Sonatype Nexus. Supports index_data and Lucene search * modes. * * @author Darren Carlson */ public class NexusSource implements IContextPluginConnector { // Private data private final String TAG = getClass().getSimpleName(); private final DefaultHttpClient client = new DefaultHttpClient(); private final RepositoryInfo[] nexusRepos; private HttpGet getRequest; private boolean cancel; public NexusSource(RepositoryInfo nexusServer) { this.nexusRepos = new RepositoryInfo[] { nexusServer }; } public NexusSource(RepositoryInfo[] nexusServers) { this.nexusRepos = nexusServers; } @Override public void cancel() { cancel = true; try { if (getRequest != null) getRequest.abort(); } catch (Exception e) { Log.w(TAG, "Exception while aborting getRequest: " + e.toString()); } } @Override public synchronized List<DiscoveredContextPlugin> getContextPlugins(PLATFORM platform, VersionInfo platformVersion, VersionInfo frameworkVersion) throws Exception { cancel = false; List<DiscoveredContextPlugin> plugs = new ArrayList<>(); for (RepositoryInfo repo : nexusRepos) { if (cancel) break; if (repo.getType().equalsIgnoreCase(RepositoryInfo.NEXUS_INDEX_SOURCE)) plugs.addAll(getPlugsFromIndexSearch(repo, platform, platformVersion, frameworkVersion)); else if (repo.getType().equalsIgnoreCase(RepositoryInfo.NEXUS_LUCENE_SOURCE)) plugs.addAll(getPlugsFromLuceneSearch(repo, platform, platformVersion, frameworkVersion)); else Log.w(TAG, "Repo type not known: " + repo.getType()); } return plugs; } /** * Extracts plug-ins from a Nexus repo using the Lucene search method. * * @param repo RepositoryInfo configured with a NEXUS_LUCENE_SOURCE type and associated url. * @return A List of DiscoveredContextPlugin(s) * @throws Exception * @See https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/rest.lucene.search.html */ private List<DiscoveredContextPlugin> getPlugsFromLuceneSearch(RepositoryInfo repo, PLATFORM platform, VersionInfo platformVersion, VersionInfo frameworkVersion) throws Exception { Serializer serializer = new Persister(); String xmlData = retrieve(repo.getUrl()); Reader reader = new StringReader(xmlData); List<DiscoveredContextPlugin> plugs = new ArrayList<>(); NexusMavenLuceneResultsBinder searchResults = serializer.read(NexusMavenLuceneResultsBinder.class, reader, false); NexusNGRepositoryDetail repoDetails = searchResults.repoDetails.repoDetail; if (searchResults != null && searchResults.totalCount > 0) { // Grab Nexus' base url (may not be at {url}/nexus/) String nexusBaseUrl = repoDetails.repositoryURL.substring(0, repoDetails.repositoryURL.indexOf("/service/local/")); for (NexusNGArtifactBinder art : searchResults.data) { // Each art should be a plug-in, if it contains a plugin and metadata classifier for (NexusNgArtifactHitBinder hit : art.artifactHits) { DiscoveredContextPlugin plug = null; // Search for the metadata for (NexusArtifactLinkBinder link : hit.artifactLinks) { if (link.isMetadata()) { try { // Grab the metadata String metaXml = retrieve(makeRetrievalUrl(nexusBaseUrl, art, hit, link)); Reader metaReader = new StringReader(metaXml); ContextPluginBinder metaResult = serializer.read(ContextPluginBinder.class, metaReader, false); metaReader.close(); DiscoveredContextPlugin tmp = metaResult.createDiscoveredPlugin(repo); if (UpdateUtils.checkCompatibility(tmp.getContextPlugin(), platform, platformVersion, frameworkVersion)) { plug = tmp; break; } } catch (Exception e) { Log.w(TAG, "Problem creating plugin for " + art + ", exception was: " + e.toString()); } } } // If we created a plugin, create the download link to the JAR if (plug != null) { boolean found = false; for (NexusArtifactLinkBinder link : hit.artifactLinks) { if (link.isPlugin()) { plug.getContextPlugin() .setInstallUrl(makeRetrievalUrl(nexusBaseUrl, art, hit, link)); if (!plugs.contains(plug)) { plugs.add(plug); break; } else { Log.w(TAG, "Plugin was already added... skipping"); } } } if (!found) { Log.w(TAG, "Could not find JAR for " + art); } } } } } return plugs; } /** * Extracts plug-ins from a Nexus repo using the (deprecated) date_index search method. * * @param repo RepositoryInfo configured with a NEXUS_INDEX_SOURCE type and associated url. * @return A List of DiscoveredContextPlugin(s) * @throws Exception * @See https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/rest.data_index.html */ private List<DiscoveredContextPlugin> getPlugsFromIndexSearch(RepositoryInfo repo, PLATFORM platform, VersionInfo platformVersion, VersionInfo frameworkVersion) throws Exception { Serializer serializer = new Persister(); String repoId = Utils.getArgumentValueFromUrl(repo.getUrl(), "repositoryId"); String xmlData = retrieve(repo.getUrl()); Reader reader = new StringReader(xmlData); List<DiscoveredContextPlugin> plugs = new ArrayList<>(); NexusSearchResultsBinder searchResults = serializer.read(NexusSearchResultsBinder.class, reader, false); if (searchResults != null && searchResults.totalCount > 0) { // Gather the metadata artifacts from the search results List<NexusArtifactBinder> metadata = new ArrayList<>(); for (NexusArtifactBinder art : searchResults.data) { if (repoId != null && art.repoId.equalsIgnoreCase(repoId)) { if (art.classifier != null && art.classifier.equalsIgnoreCase("metadata")) if (!metadata.contains(art)) metadata.add(art); else Log.w(TAG, "Already stored metadata for ID: " + art.getId()); } } // Next gather the plugin artifacts for each associated metadata artifact Map<NexusArtifactBinder, NexusArtifactBinder> metaMap = new HashMap<>(); for (NexusArtifactBinder meta : metadata) { for (NexusArtifactBinder art : searchResults.data) { if (repoId != null && art.repoId.equalsIgnoreCase(repoId)) { if (art.classifier != null && art.classifier.equalsIgnoreCase("plugin") && art.getId().equalsIgnoreCase(meta.getId()) && art.version.equalsIgnoreCase(meta.version)) { if (!metaMap.keySet().contains(meta)) metaMap.put(meta, art); else Log.w(TAG, "Already stored plugin for ID: " + meta.getId()); break; } } } } /* * Now create the plug-ins using the metadata and the download URIs from the artifacts */ for (NexusArtifactBinder metaBinder : metaMap.keySet()) { /* * Steps: 1. Download the metadata file 2. De-serialize it to create a template 3. Use the values from * the template to construct a ContextPlugin 4. Use the associated pluging uri to update the * ContextPlugin download link */ NexusArtifactBinder plugBinder = metaMap.get(metaBinder); if (plugBinder != null) { try { String metaXml = retrieve(metaBinder.resourceURI); Reader metaReader = new StringReader(metaXml); ContextPluginBinder metaResult = serializer.read(ContextPluginBinder.class, metaReader, false); metaReader.close(); if (metaResult.repoType.equals("nexus-rest")) { metaResult.installUrl = plugBinder.resourceURI; metaResult.updateUrl = plugBinder.artifactLink; } DiscoveredContextPlugin plug = metaResult.createDiscoveredPlugin(repo); if (UpdateUtils.checkCompatibility(plug.getContextPlugin(), platform, platformVersion, frameworkVersion)) { if (!plugs.contains(plug)) { plugs.add(plug); } else { Log.w(TAG, "Plugin was already added... skipping"); } } } catch (Exception e) { Log.w(TAG, "Problem parsing plugin metadata for: " + metaBinder.getId() + " | " + e.toString()); } } else { Log.w(TAG, "Could not find plugBinder for: " + metaBinder); } } } return plugs; } /** * Utility for downloading XML-based resources using HttpGet. * * @param url The URL of the XML resource to download. * @return The XML resource as a string, or null if the resource could not be downloaded. */ private String retrieve(String url) { if (!cancel) { getRequest = new HttpGet(url); try { HttpResponse getResponse = client.execute(getRequest); final int statusCode = getResponse.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Log.w(getClass().getSimpleName(), "HTTP fail with status code: " + statusCode); return null; } HttpEntity getResponseEntity = getResponse.getEntity(); if (getResponseEntity != null) { return EntityUtils.toString(getResponseEntity); } } catch (IOException e) { getRequest.abort(); Log.w(TAG, "Error for URL " + url, e); } } return null; } /** * Utility for creating a Nexus retrieval url * * @param nexusBaseUrl The base url of the Nexus instance * @param art The NexusNGArtifactBinder * @param hit The NexusNgArtifactHitBinder * @param link The NexusArtifactLinkBinder * @return A retrieval url for the artifact * @see https://repository.sonatype.org/nexus-core-documentation-plugin/core/docs/rest.artifact.maven.content.html */ private String makeRetrievalUrl(String nexusBaseUrl, NexusNGArtifactBinder art, NexusNgArtifactHitBinder hit, NexusArtifactLinkBinder link) { return nexusBaseUrl + "/service/local/artifact/maven/content?r=" + hit.repositoryId + "&g=" + art.groupId + "&a=" + art.artifactId + "&v=" + art.version + "&c=" + link.classifier + "&e=" + link.extension; } }