FELIX-1988 Apply 20.obr_plugin.patch by Valentin Valchev (thanks) (fixed license header of BundleRepositoryRender)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@912369 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java
deleted file mode 100644
index 6cf16fa..0000000
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.felix.webconsole.internal.obr;
-
-
-import org.apache.felix.webconsole.internal.BaseManagementPlugin;
-import org.osgi.service.log.LogService;
-import org.osgi.service.obr.RepositoryAdmin;
-import org.osgi.util.tracker.ServiceTracker;
-
-
-public class AbstractObrPlugin extends BaseManagementPlugin
-{
-
- // track the optional installer service manually
- private ServiceTracker repositoryAdmin;
-
- // marker indicating a special version to not install anything
- protected static final String DONT_INSTALL_OPTION = "-";
-
- protected RepositoryAdmin getRepositoryAdmin()
- {
- if ( repositoryAdmin == null )
- {
- try
- {
- repositoryAdmin = new ServiceTracker( getBundleContext(), RepositoryAdmin.class.getName(), null );
- repositoryAdmin.open();
- }
- catch ( Throwable t )
- {
- getLog().log( LogService.LOG_WARNING, "Cannot create RepositoryAdmin service tracker", t );
- return null;
- }
-
- }
-
- return ( RepositoryAdmin ) repositoryAdmin.getService();
- }
-
-}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
index 3609331..c87fa69 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
@@ -1,437 +1,293 @@
/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ * 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.
+ * 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.apache.felix.webconsole.internal.obr;
-
import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
+import java.net.URL;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
-import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.DefaultVariableResolver;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
+import org.apache.felix.webconsole.WebConsoleUtil;
+import org.apache.felix.webconsole.internal.Logger;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
import org.osgi.service.obr.Repository;
import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Resolver;
import org.osgi.service.obr.Resource;
-
-public class BundleRepositoryRender extends BaseWebConsolePlugin
+/**
+ * This class provides a plugin for rendering the available OSGi Bundle Repositories
+ * and the resources they provide.
+ */
+public class BundleRepositoryRender extends SimpleWebConsolePlugin implements OsgiManagerPlugin
{
+ private static final String LABEL = "obr";
+ private static final String TITLE = "OSGi Repository";
+ private static final String[] CSS = null;
- public static final String LABEL = "bundlerepo";
+ // templates
+ private final String TEMPLATE;
- public static final String TITLE = "OSGi Repository";
-
- public static final String PARAM_REPO_ID = "repositoryId";
-
- public static final String PARAM_REPO_URL = "repositoryURL";
-
- private static final String REPOSITORY_PROPERTY = "obr.repository.url";
-
- private static final String ALL_CATEGORIES_OPTION = "*";
-
- private static final String NO_CATEGORIES_OPTION = "---";
-
- private static final String PAR_CATEGORIES = "category";
-
- private String[] repoURLs;
-
-
- public void activate( BundleContext bundleContext )
+ /**
+ *
+ */
+ public BundleRepositoryRender()
{
- super.activate( bundleContext );
+ super(LABEL, TITLE, CSS);
- String urlStr = bundleContext.getProperty( REPOSITORY_PROPERTY );
- List urlList = new ArrayList();
-
- if ( urlStr != null )
- {
- StringTokenizer st = new StringTokenizer( urlStr );
- while ( st.hasMoreTokens() )
- {
- urlList.add( st.nextToken() );
- }
- }
-
- this.repoURLs = ( String[] ) urlList.toArray( new String[urlList.size()] );
+ // load templates
+ TEMPLATE = readTemplateFile("/templates/obr.html");
}
-
- public String getLabel()
- {
- return LABEL;
- }
-
-
- public String getTitle()
- {
- return TITLE;
- }
-
-
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#renderContent(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
+ // prepare variables
+ DefaultVariableResolver vars = ((DefaultVariableResolver) WebConsoleUtil.getVariableResolver(request));
+ vars.put("__data__", getData());
- PrintWriter pw = response.getWriter();
- this.header( pw );
+ response.getWriter().print(TEMPLATE);
+ }
- RepositoryAdmin repoAdmin = getRepositoryAdmin();
- if ( repoAdmin == null )
+ /**
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ final RepositoryAdmin admin = getRepositoryAdmin();
+
+ if (admin == null)
{
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content' colspan='4'>RepositoryAdmin Service not available</td>" );
- pw.println( "</tr>" );
-
- footer( pw );
-
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ "RepositoryAdmin service is missing");
return;
}
- Repository[] repos = repoAdmin.listRepositories();
- Set activeURLs = new HashSet();
- if ( repos == null || repos.length == 0 )
+ final String action = request.getParameter("action");
+ final String deploy = request.getParameter("deploy");
+ final String deploystart = request.getParameter("deploystart");
+
+ if (action != null)
{
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content' colspan='4'>No Active Repositories</td>" );
- pw.println( "</tr>" );
+ doAction(action, request.getParameter("url"), admin);
+ response.getWriter().print(getData());
+ return;
}
- else
+
+ if (deploy != null || deploystart != null)
{
- for ( int i = 0; i < repos.length; i++ )
+ doDeploy(request.getParameterValues("bundle"), deploystart != null, admin);
+ doGet(request, response);
+ return;
+ }
+
+ super.doPost(request, response);
+ }
+
+ private final RepositoryAdmin getRepositoryAdmin()
+ {
+ try
+ {
+ return (RepositoryAdmin) super.getService(RepositoryAdmin.class.getName());
+ }
+ catch (Throwable t)
+ {
+ log("Cannot create RepositoryAdmin service tracker", t);
+ return null;
+ }
+ }
+
+ private final String getData()
+ {
+ final Bundle[] bundles = getBundleContext().getBundles();
+ try
+ {
+ return toJSON(getRepositoryAdmin(), bundles).toString();
+ }
+ catch (JSONException e)
+ {
+ log("Failed to serialize repository to JSON object.", e);
+ return "";
+ }
+
+ }
+
+ private final void doAction(String action, String urlParam, RepositoryAdmin admin)
+ throws IOException, ServletException
+ {
+ Repository[] repos = admin.listRepositories();
+ Repository repo = getRepository(repos, urlParam);
+
+ URL url = repo != null ? repo.getURL() : new URL(urlParam);
+
+ if ("delete".equals(action))
+ {
+ if (!admin.removeRepository(url))
{
- Repository repo = repos[i];
+ throw new ServletException("Failed to remove repository with URL " + url);
+ }
+ }
+ else if ("add".equals(action) || "refresh".equals(action))
+ {
+ try
+ {
+ admin.addRepository(url);
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new ServletException("Failed to " + action + " repository " + url
+ + ": " + e.toString());
+ }
- activeURLs.add( repo.getURL().toString() );
+ }
+ }
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content'>" + repo.getName() + "</td>" );
+ private final void doDeploy(String[] bundles, boolean start, RepositoryAdmin repoAdmin)
+ {
+ // check whether we have to do something
+ if (bundles == null || bundles.length == 0)
+ {
+ log("No resources to deploy");
+ return;
+ }
- pw.print( "<td class='content'>" );
- pw.print( "<a href='" + repo.getURL() + "' target='_blank' title='Show Repository " + repo.getURL()
- + "'>" + repo.getURL() + "</a>" );
- pw.println( "</td>" );
+ Resolver resolver = repoAdmin.resolver();
- pw.println( "<td class='content'>" + new Date( repo.getLastModified() ) + "</td>" );
- pw.println( "<td class='content'>" );
- pw.println( "<form>" );
- pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + RefreshRepoAction.NAME
- + "'>" );
- pw.println( "<input type='hidden' name='" + RefreshRepoAction.PARAM_REPO + "' value='" + repo.getURL()
- + "'>" );
- pw.println( "<input class='submit' type='submit' value='Refresh'>" );
- pw.println( "<input class='submit' type='submit' name='remove' value='Remove'>" );
- pw.println( "</form>" );
- pw.println( "</td>" );
- pw.println( "</tr>" );
+ // prepare the deployment
+ for (int i = 0; i < bundles.length; i++)
+ {
+ String bundle = bundles[i];
+ if (bundle == null || bundle.equals("-"))
+ {
+ continue;
+ }
+
+ String filter = "(id=" + bundle + ")";
+ Resource[] resources = repoAdmin.discoverResources(filter);
+ if (resources != null && resources.length > 0)
+ {
+ resolver.add(resources[0]);
}
}
- // list any repositories configured but not active
- for ( int i = 0; i < this.repoURLs.length; i++ )
+ DeployerThread dt = new DeployerThread(resolver, new Logger(getBundleContext()),
+ start);
+ dt.start();
+ }
+
+ private static final Repository getRepository(Repository[] repos, String repositoryUrl)
+ {
+ if (repositoryUrl == null || repositoryUrl.length() == 0)
{
- if ( !activeURLs.contains( this.repoURLs[i] ) )
+ return null;
+ }
+
+ for (int i = 0; i < repos.length; i++)
+ {
+ if (repositoryUrl.equals(repos[i].getURL().toString()))
{
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content'>-</td>" );
- pw.println( "<td class='content'>" + this.repoURLs[i] + "</td>" );
- pw.println( "<td class='content'>[inactive, click Refresh to activate]</td>" );
- pw.println( "<td class='content'>" );
- pw.println( "<form>" );
- pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + RefreshRepoAction.NAME
- + "'>" );
- pw.println( "<input type='hidden' name='" + RefreshRepoAction.PARAM_REPO + "' value='"
- + this.repoURLs[i] + "'>" );
- pw.println( "<input class='submit' type='submit' value='Refresh'>" );
- pw.println( "</form>" );
- pw.println( "</td>" );
- pw.println( "</tr>" );
+ return repos[i];
}
}
- // entry of a new repository
- pw.println( "<form>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content'> </td>" );
- pw.println( "<td class='content' colspan='2'>" );
- pw.println( " <input class='input' type='text' name='" + RefreshRepoAction.PARAM_REPO
- + "' value='' size='80'>" );
- pw.println( "</td>" );
- pw.println( "<td class='content'>" );
- pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + RefreshRepoAction.NAME + "'>" );
- pw.println( "<input class='submit' type='submit' value='Add'>" );
- pw.println( "</td>" );
- pw.println( "</tr>" );
- pw.println( "</form>" );
-
- this.footer( pw );
-
- this.listResources( pw, repos, request.getParameter( PAR_CATEGORIES ) );
+ return null;
}
-
- private void header( PrintWriter pw )
+ private static final JSONObject toJSON(RepositoryAdmin admin, Bundle[] bundles)
+ throws JSONException
{
- pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<th class='content container' colspan='4'>Bundle Repositories</th>" );
- pw.println( "</tr>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<th class='content'>Name</th>" );
- pw.println( "<th class='content'>URL</th>" );
- pw.println( "<th class='content'>Last Modification Time</th>" );
- pw.println( "<th class='content'> </th>" );
- pw.println( "</tr>" );
- }
+ JSONObject json = new JSONObject();
+ json.put("status", admin != null);
-
- private void footer( PrintWriter pw )
- {
- pw.println( "</table>" );
- }
-
-
- private void listResources( PrintWriter pw, Repository[] repos, String category )
- {
-
- // assume no category if the all option
- if ( ALL_CATEGORIES_OPTION.equals( category ) )
+ if (admin != null)
{
- category = null;
- }
-
- Map bundles = this.getBundles();
-
- Map resSet = new HashMap();
- SortedSet categories = new TreeSet();
- SortedSet labels = new TreeSet();
-
- for ( int i = 0; i < repos.length; i++ )
- {
- Resource[] resources = repos[i].getResources();
- for ( int j = 0; resources != null && j < resources.length; j++ )
+ final Repository repositories[] = admin.listRepositories();
+ for (int i = 0; repositories != null && i < repositories.length; i++)
{
- Resource res = resources[j];
-
- // get categories and check whether we should actually
- // ignore this resource
- boolean useResource;
- final String[] cats = res.getCategories();
- if ( cats == null )
- {
- useResource = NO_CATEGORIES_OPTION.equals( category );
- }
- else
- {
- useResource = false;
- for ( int ci = 0; cats != null && ci < cats.length; ci++ )
- {
- String cat = cats[ci];
- categories.add( cat );
- useResource |= ( category == null || cat.equals( category ) );
- }
- }
-
- if ( useResource )
- {
- String symbolicName = res.getSymbolicName();
- Version version = res.getVersion();
- Version installedVersion = ( Version ) bundles.get( symbolicName );
- if ( installedVersion == null || installedVersion.compareTo( version ) < 0 )
- {
- Collection versions = ( Collection ) resSet.get( symbolicName );
- if ( versions == null )
- {
- // order versions, hence use a TreeSet
- versions = new TreeSet();
- resSet.put( symbolicName, versions );
- }
- versions.add( version );
-
- labels.add( res.getPresentationName() + Character.MAX_VALUE + symbolicName );
- }
- }
+ json.append("repositories", toJSON(repositories[i], bundles));
}
}
- boolean doForm = !resSet.isEmpty();
- this.resourcesHeader( pw, doForm, category, categories );
+ return json;
- for ( Iterator ri = labels.iterator(); ri.hasNext(); )
- {
- final String label = ( String ) ri.next();
- final int idx = label.indexOf( Character.MAX_VALUE );
- final String presName = label.substring( 0, idx );
- final String symName = label.substring( idx + 1 );
- final Collection versions = ( Collection ) resSet.remove( symName );
- if ( versions != null )
- {
- this.printResource( pw, symName, presName, versions );
- }
- }
-
- this.resourcesFooter( pw, doForm );
}
-
- private void resourcesHeader( PrintWriter pw, boolean doForm, String currentCategory, Collection categories )
+ private static final JSONObject toJSON(Repository repo, Bundle[] bundles)
+ throws JSONException
{
+ JSONObject json = new JSONObject() //
+ .put("lastModified", repo.getLastModified()) //
+ .put("name", repo.getName()) //
+ .put("url", repo.getURL()); //
- if ( doForm )
+ Resource[] resources = repo.getResources();
+ for (int i = 0; resources != null && i < resources.length; i++)
{
- pw.println( "<form method='post'>" );
- pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + InstallFromRepoAction.NAME
- + "'>" );
+ json.append("resources", toJSON(resources[i], bundles));
}
- pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<th class='content container'>Available Resources</th>" );
-
- if ( categories != null && !categories.isEmpty() )
- {
- pw.println( "<th class='content container' style='text-align:right'>Limit to Bundle Category:</th>" );
- pw.println( "<th class='content container'>" );
- Util.startScript( pw );
- pw.println( "function reloadWithCat(field) {" );
- pw.println( " var query = '?" + PAR_CATEGORIES + "=' + field.value;" );
- pw
- .println( " var dest = document.location.protocol + '//' + document.location.host + document.location.pathname + query;" );
- pw.println( " document.location = dest;" );
- pw.println( "}" );
- Util.endScript( pw );
- pw.println( "<select class='select' name='__ignoreoption__' onChange='reloadWithCat(this);'>" );
- pw.print( "<option value='" + ALL_CATEGORIES_OPTION + "'>all</option>" );
- pw.print( "<option value='" + NO_CATEGORIES_OPTION + "'>none</option>" );
- for ( Iterator ci = categories.iterator(); ci.hasNext(); )
- {
- String category = ( String ) ci.next();
- pw.print( "<option value='" + category + "'" );
- if ( category.equals( currentCategory ) )
- {
- pw.print( " selected" );
- }
- pw.print( '>' );
- pw.print( category );
- pw.println( "</option>" );
- }
- pw.println( "</select>" );
- pw.println( "</th>" );
- }
- else
- {
- pw.println( "<th class='content container'> </th>" );
- }
-
- pw.println( "</tr>" );
- pw.println( "<tr class='content'>" );
- pw.println( "<th class='content'>Deploy Version</th>" );
- pw.println( "<th class='content' colspan='2'>Name</th>" );
- pw.println( "</tr>" );
+ return json;
}
-
- private void printResource( PrintWriter pw, String symbolicName, String presentationName, Collection versions )
+ private static final JSONObject toJSON(Resource resource, Bundle[] bundles)
+ throws JSONException
{
- pw.println( "<tr class='content'>" );
-
- pw.println( "<td class='content' valign='top' align='center'>" );
- pw.println( "<select class='select' name='bundle'>" );
- pw.print( "<option value='" + AbstractObrPlugin.DONT_INSTALL_OPTION + "'>Select Version...</option>" );
- for ( Iterator vi = versions.iterator(); vi.hasNext(); )
+ final String symbolicName = resource.getSymbolicName();
+ final String version = resource.getVersion().toString();
+ boolean installed = false;
+ for (int i = 0; symbolicName != null && !installed && bundles != null
+ && i < bundles.length; i++)
{
- Version version = ( Version ) vi.next();
- pw.print( "<option value='" + symbolicName + "," + version + "'>" );
- pw.print( version );
- pw.println( "</option>" );
+ final String ver = (String) bundles[i].getHeaders("").get(
+ Constants.BUNDLE_VERSION);
+ installed = symbolicName.equals(bundles[i].getSymbolicName())
+ && version.equals(ver);
}
- pw.println( "</select>" );
- pw.println( "</td>" );
+ JSONObject json = new JSONObject(resource.getProperties()) //
+ .put("id", resource.getId()) //
+ .put("presentationname", resource.getPresentationName()) //
+ .put("symbolicname", symbolicName) //
+ .put("url", resource.getURL()) //
+ .put("version", version) //
+ .put("url", resource.getURL()) //
+ .put("categories", resource.getCategories()) //
+ .put("installed", installed);
- pw.println( "<td class='content' colspan='2'>" + presentationName + " (" + symbolicName + ")</td>" );
-
- pw.println( "</tr>" );
- }
-
-
- private void resourcesButtons( PrintWriter pw )
- {
- pw.println( "<tr class='content'>" );
- pw.println( "<td class='content'> </td>" );
- pw.println( "<td class='content'>" );
- pw.println( "<input class='submit' style='width:auto' type='submit' name='deploy' value='Deploy Selected'>" );
- pw.println( " " );
- pw
- .println( "<input class='submit' style='width:auto' type='submit' name='deploystart' value='Deploy and Start Selected'>" );
- pw.println( "</td></tr>" );
- }
-
-
- private void resourcesFooter( PrintWriter pw, boolean doForm )
- {
- if ( doForm )
- {
- this.resourcesButtons( pw );
- }
- pw.println( "</table></form>" );
- }
-
-
- private Map getBundles()
- {
- Map bundles = new HashMap();
-
- Bundle[] installed = getBundleContext().getBundles();
- for ( int i = 0; i < installed.length; i++ )
- {
- String ver = ( String ) installed[i].getHeaders().get( Constants.BUNDLE_VERSION );
- Version bundleVersion = Version.parseVersion( ver );
-
- // assume one bundle instance per symbolic name !!
- // only add if there is a symbolic name !
- if ( installed[i].getSymbolicName() != null )
- {
- bundles.put( installed[i].getSymbolicName(), bundleVersion );
- }
- }
-
- return bundles;
- }
-
-
- protected RepositoryAdmin getRepositoryAdmin()
- {
- return ( RepositoryAdmin ) getService( "org.osgi.service.obr.RepositoryAdmin" );
+ // TODO: do we need these ?
+ // resource.getCapabilities()
+ // resource.getRequirements()
+ return json;
}
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java
deleted file mode 100644
index 165cdb4..0000000
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.felix.webconsole.internal.obr;
-
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.felix.webconsole.Action;
-import org.osgi.service.log.LogService;
-import org.osgi.service.obr.RepositoryAdmin;
-import org.osgi.service.obr.Resolver;
-import org.osgi.service.obr.Resource;
-
-
-public class InstallFromRepoAction extends AbstractObrPlugin implements Action
-{
-
- public static final String NAME = "installFromOBR";
-
-
- public String getName()
- {
- return NAME;
- }
-
-
- public String getLabel()
- {
- return NAME;
- }
-
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.sling.manager.web.internal.Action#performAction(javax.servlet.http.HttpServletRequest,
- * javax.servlet.http.HttpServletResponse)
- */
- public boolean performAction( HttpServletRequest request, HttpServletResponse response )
- {
-
- // check whether we have to do something
- String[] bundles = request.getParameterValues( "bundle" );
- if ( bundles == null || bundles.length == 0 )
- {
- getLog().log( LogService.LOG_INFO, "No resources to deploy" );
- return true;
- }
-
- RepositoryAdmin repoAdmin = getRepositoryAdmin();
- if ( repoAdmin != null )
- {
-
- Resolver resolver = repoAdmin.resolver();
-
- // prepare the deployment
- for ( int i = 0; i < bundles.length; i++ )
- {
- String bundle = bundles[i];
- if ( bundle == null || bundle.equals( DONT_INSTALL_OPTION ) )
- {
- continue;
- }
-
- int comma = bundle.indexOf( ',' );
- String name = ( comma > 0 ) ? bundle.substring( 0, comma ) : bundle;
- String version = ( comma < bundle.length() - 1 ) ? bundle.substring( comma + 1 ) : null;
-
- if ( name.length() > 0 )
- {
- // no name, ignore this one
- if ( version == null )
- {
- version = "*";
- }
-
- String filter = "(&(symbolicname=" + name + ")(version=" + version + "))";
- Resource[] resources = repoAdmin.discoverResources( filter );
- if ( resources != null && resources.length > 0 )
- {
- resolver.add( resources[0] );
- }
- }
-
- }
-
- // check whether the "deploystart" button was clicked
- boolean start = request.getParameter( "deploystart" ) != null;
-
- DeployerThread dt = new DeployerThread( resolver, getLog(), start );
- dt.start();
- }
-
- // redirect to bundle list
- return true;
- }
-}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java
deleted file mode 100644
index 1917b00..0000000
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.felix.webconsole.internal.obr;
-
-
-import java.net.URL;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.felix.webconsole.Action;
-import org.osgi.service.log.LogService;
-import org.osgi.service.obr.Repository;
-import org.osgi.service.obr.RepositoryAdmin;
-
-
-public class RefreshRepoAction extends AbstractObrPlugin implements Action
-{
-
- public static final String NAME = "refreshOBR";
-
- public static final String PARAM_REPO = "repository";
-
-
- public String getName()
- {
- return NAME;
- }
-
-
- public String getLabel()
- {
- return NAME;
- }
-
-
- public boolean performAction( HttpServletRequest request, HttpServletResponse response )
- {
-
- RepositoryAdmin repoAdmin = getRepositoryAdmin();
- if ( repoAdmin != null )
- {
- String repositoryURL = request.getParameter( "repository" );
- Repository[] repos = repoAdmin.listRepositories();
- Repository repo = this.getRepository( repos, repositoryURL );
-
- URL repoURL = null;
- if ( repo != null )
- {
- repoURL = repo.getURL();
- }
- else
- {
- try
- {
- repoURL = new URL( repositoryURL );
- }
- catch ( Throwable t )
- {
- getLog().log( LogService.LOG_ERROR,
- "RefreshRepoAction: Submitted URL " + repositoryURL + " is invalid: " + t.getMessage() );
- }
- }
-
- // log.log(LogService.LOG_DEBUG, "Refreshing " + repo.getURL());
- if ( repoURL != null )
- {
- if ( request.getParameter( "remove" ) != null )
- {
- try
- {
- repoAdmin.removeRepository( repoURL );
- getLog().log( LogService.LOG_INFO, "RefreshRepoAction: Removed repository " + repositoryURL );
- }
- catch ( Exception e )
- {
- getLog().log( LogService.LOG_ERROR,
- "RefreshRepoAction: Failed removing repository " + repositoryURL, e );
- }
- }
- else
- {
- try
- {
- repoAdmin.addRepository( repoURL );
- getLog().log( LogService.LOG_INFO, "RefreshRepoAction: Added repository " + repositoryURL );
- }
- catch ( Exception e )
- {
- getLog().log( LogService.LOG_ERROR,
- "RefreshRepoAction: Failed adding repository " + repositoryURL, e );
- }
- }
- }
- }
-
- return true;
- }
-
-
- // ---------- internal -----------------------------------------------------
-
- private Repository getRepository( Repository[] repos, String repositoryUrl )
- {
- if ( repositoryUrl == null || repositoryUrl.length() == 0 )
- {
- return null;
- }
-
- for ( int i = 0; i < repos.length; i++ )
- {
- if ( repositoryUrl.equals( repos[i].getURL().toString() ) )
- {
- return repos[i];
- }
- }
-
- return null;
- }
-}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 8a64a14..3061693 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -139,8 +139,6 @@
"org.apache.felix.webconsole.internal.misc.ConfigurationRender",
"org.apache.felix.webconsole.internal.misc.ShellServlet",
"org.apache.felix.webconsole.internal.obr.BundleRepositoryRender",
- "org.apache.felix.webconsole.internal.obr.InstallFromRepoAction",
- "org.apache.felix.webconsole.internal.obr.RefreshRepoAction",
"org.apache.felix.webconsole.internal.system.GCAction",
"org.apache.felix.webconsole.internal.system.VMStatPlugin"
};
diff --git a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
index cac6186..48ea630 100644
--- a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -40,6 +40,7 @@
save=Save
reset=Reset
delete=Delete
+refresh=Refresh
# VMStat plugin
vmstat.stopped=Framework has been stopped.
@@ -171,4 +172,21 @@
license.status.ok=The following bundles contains license files.
license.status.none=No bundles with license files available
license.resources=Bundle Resources:
-license.resources.embedded=Embedded {0}:
\ No newline at end of file
+license.resources.embedded=Embedded {0}:
+
+# OBR Plugin
+obr.status.ok=The Apache Bundle Repository service is up and running.
+obr.status.no=The Apache Bundle Repository service is not available!
+obr.version.select=Select Version...
+obr.repo.title=Bundle Repositories
+obr.action.add=Add
+obr.action.search=Search
+obr.action.deploy=Deploy Selected
+obr.action.deploystart=Deploy and Start Selected
+obr.repo.name=Name
+obr.repo.url=URL
+obr.repo.lastModified=Last Modified
+obr.repo.actions=Actions
+obr.res.title=Available Resources
+obr.res.name=Resource Name
+obr.res.installedVer=Installed Version
diff --git a/webconsole/src/main/resources/res/lib/support.js b/webconsole/src/main/resources/res/lib/support.js
index 8b161c8..67078f0 100644
--- a/webconsole/src/main/resources/res/lib/support.js
+++ b/webconsole/src/main/resources/res/lib/support.js
@@ -70,11 +70,8 @@
);
// register global ajax error handler
- $(document).ajaxError( function(event, XMLHttpRequest, ajaxOptions, thrownError) {
- var pre = '<br/><pre>';
- for (i in event) pre += i + '=' + event[i] + '\n'
- pre += '</pre>';
- Xalert('The request failed: ' + thrownError + pre, 'AJAX Error');
+ $(document).ajaxError( function(event, req) {
+ Xalert('The request failed: <br/><pre>' + req.statusText + '</pre>', 'AJAX Error');
});
initStaticWidgets();
@@ -127,6 +124,7 @@
Xdialog(text).dialog({
modal: true,
title: title,
+ width: '70%',
buttons: {
"Ok": function() {
$(this).dialog('close');
diff --git a/webconsole/src/main/resources/res/ui/obr.js b/webconsole/src/main/resources/res/ui/obr.js
new file mode 100644
index 0000000..53e532b
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/obr.js
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+var repoTable = false;
+var repoTableTemplate = false;
+var addRepoUri = false;
+var resTable = false;
+var searchField = false;
+
+/* displays a date in the user's local timezone */
+function localTm(time) {
+ return (time ? new Date(time) : new Date()).toLocaleString();
+}
+
+function doRepoAction(action, url) {
+ if ( !url ) {
+ Xalert('Invalid URI: ' + url, 'Error');
+ } else {
+ $.post(pluginRoot, {
+ 'action' : action,
+ 'url' : url
+ }, renderData, 'json');
+ }
+}
+
+function renderResource(res) {
+ // aply filtering
+ var match = searchField.val();
+ if (match) {
+ match = new RegExp( match );
+ if ( !match.test(res.presentationname) ) return;
+ }
+
+ // proceed with resource
+ var _id = res.symbolicname.replace(/\./g, '_');
+ var _tr = resTable.find('#' + _id);
+
+ if (_tr.length == 0) { // not created yet, create it
+ var _select = createElement('select', null, { name : 'bundle' }, [
+ createElement( 'option', null, { value : '-' }, [
+ text( i18n.selectVersion)
+ ]),
+ createElement( 'option', null, { value : res.id }, [
+ text( res.version + (res.installed ? ' *' : '') )
+ ])
+ ]);
+ _tr = tr( null, { 'id' : _id } , [
+ td( null, null, [ _select ] ),
+ td( null, null, [ text(res.presentationname) ] ),
+ td( null, null, [ text(res.installed ? res.version : '') ] )
+ ]);
+ resTable.append( _tr );
+ } else { // append the additional version
+ _tr.find( 'select' ).append (
+ createElement( 'option', null, { value : res.id }, [
+ text( res.version + (res.installed ? ' *' : '') )
+ ])
+ );
+ if (res.installed) _tr.find( 'td:eq(2)' ).text( res.version );
+ }
+}
+
+function renderRepository(repo) {
+ var _tr = repoTableTemplate.clone();
+ _tr.find('td:eq(0)').text( repo.name );
+ _tr.find('td:eq(1)').text( repo.url );
+ _tr.find('td:eq(2)').text( localTm(repo.lastModified) );
+ _tr.find('li:eq(0)').click(function() {
+ doRepoAction('refresh', repo.url);
+ });
+ _tr.find('li:eq(1)').click(function() {
+ doRepoAction('delete', repo.url);
+ });
+ repoTable.append(_tr);
+
+ for(var i in repo.resources) {
+ renderResource( repo.resources[i] );
+ }
+}
+
+function renderData(data) {
+ obrData = data;
+ repoTable.empty();
+ resTable.empty();
+ if ( data.status ) {
+ $('.statline').html(i18n.status_ok);
+ for (var i in data.repositories ) {
+ renderRepository( data.repositories[i] );
+ }
+ } else {
+ $('.statline').html(i18n.status_no);
+ }
+}
+
+$(document).ready( function() {
+ repoTable = $('#repoTable tbody');
+ repoTableTemplate = repoTable.find('tr').clone();
+ addRepoUri = $('#addRepoUri');
+ resTable = $('#resTable tbody').empty();
+ searchField = $('#searchField');
+
+ $('#addRepoBtn').click(function() {
+ doRepoAction('add', addRepoUri.val());
+ });
+ $('#searchBtn').click(function() {
+ renderData(obrData);
+ return false;
+ });
+
+ renderData(obrData);
+});
\ No newline at end of file
diff --git a/webconsole/src/main/resources/templates/obr.html b/webconsole/src/main/resources/templates/obr.html
new file mode 100644
index 0000000..12eb3bf
--- /dev/null
+++ b/webconsole/src/main/resources/templates/obr.html
@@ -0,0 +1,68 @@
+<script type="text/javascript" src="res/ui/obr.js"></script>
+<script type="text/javascript">
+var i18n = {
+ status_ok : '${obr.status.ok}',
+ status_no : '${obr.status.no}',
+ selectVersion : '${obr.version.select}'
+}
+var obrData = ${__data__};
+</script>
+
+<p class="statline">${obr.status.ok}</p>
+
+<div class="ui-widget-header ui-corner-top buttonGroup">
+ <span style="float: left; margin-left: 1em">${obr.repo.title}</span>
+ <input style="width: 50%" type="text" id="addRepoUri" />
+ <button id="addRepoBtn">${obr.action.add}</button>
+</div>
+
+<table id="repoTable" class="nicetable">
+ <thead>
+ <tr>
+ <th class="col_Name">${obr.repo.name}</th>
+ <th class="col_URL">${obr.repo.url}</th>
+ <th class="col_lastMod">${obr.repo.lastModified}</th>
+ <th class="col_Actions">${obr.repo.actions}</th>
+ </tr>
+ </thead>
+ <tbody> <!-- template: will be replaced dynamically by JS -->
+ <tr>
+ <td>name</td>
+ <td>url</td>
+ <td>date</td>
+ <td>
+ <ul class="icons ui-widget">
+ <li class="dynhover" title="${refresh}"><span class="ui-icon ui-icon-refresh"> </span></li>
+ <li class="dynhover" title="${delete}"><span class="ui-icon ui-icon-trash"> </span></li>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<br/>
+
+<form id="installForm" method="post" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <span style="float: left; margin-left: 1em">${obr.res.title}</span>
+ <input type="text" id="searchField" />
+ <button id="searchBtn">${obr.action.search}</button>
+ <input type="submit" name="deploy" value="${obr.action.deploy}" />
+ <input type="submit" name="deploystart" value="${obr.action.deploystart}" />
+ </div>
+
+ <table id="resTable" class="nicetable">
+ <thead>
+ <tr>
+ <th class="col_Version">${version}</th>
+ <th class="col_ResName">${obr.res.name}</th>
+ <th class="col_VersionInst">${obr.res.installedVer}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td colspan="2">dummy</td></tr>
+ </tbody>
+ </table>
+</form>
+
+<br/>
\ No newline at end of file