Author: gnodet
Date: Tue Jan 18 08:54:31 2011
New Revision: 1060242
URL: http://svn.apache.org/viewvc?rev=1060242&view=rev
Log:
[KARAF-317] Minor improvements to the dev:watch command to be more verbose
(it's a dev tool)
Added:
karaf/trunk/shell/dev/src/main/resources/org/apache/karaf/shell/dev/watch.txt
Modified:
karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/Watch.java
karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/watch/BundleWatcher.java
karaf/trunk/shell/dev/src/main/resources/OSGI-INF/blueprint/shell-dev.xml
Modified:
karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/Watch.java
URL:
http://svn.apache.org/viewvc/karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/Watch.java?rev=1060242&r1=1060241&r2=1060242&view=diff
==============================================================================
--- karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/Watch.java
(original)
+++ karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/Watch.java
Tue Jan 18 08:54:31 2011
@@ -16,6 +16,8 @@
*/
package org.apache.karaf.shell.dev;
+import java.util.List;
+
import org.apache.felix.gogo.commands.Argument;
import org.apache.felix.gogo.commands.Command;
import org.apache.felix.gogo.commands.Option;
@@ -24,9 +26,7 @@ import org.apache.karaf.shell.dev.watch.
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
-import java.util.List;
-
-@Command(scope = "dev", name = "watch", description = "Watch and Update
bundles")
+@Command(scope = "dev", name = "watch", description = "Watch and Update
bundles", detailedDescription="classpath:watch.txt")
public class Watch extends OsgiCommandSupport {
@Argument(index = 0, name = "urls", description = "The bundle URLs",
required = false)
@@ -35,7 +35,7 @@ public class Watch extends OsgiCommandSu
@Option(name = "-i", aliases = {}, description = "Watch interval",
required = false, multiValued = false)
private long interval;
- @Option(name = "--start", description = "Starts watching the selcted
bundles", required = false, multiValued = false)
+ @Option(name = "--start", description = "Starts watching the selected
bundles", required = false, multiValued = false)
protected boolean start;
@Option(name = "--stop", description = "Stops watching all bundles",
required = false, multiValued = false)
@@ -51,14 +51,32 @@ public class Watch extends OsgiCommandSu
@Override
protected Object doExecute() throws Exception {
- if (urls == null && (interval == 0 && !stop && !start && !list)) {
- System.out.println("No option specified. Bundle id/url is
required.");
+ if (start && stop) {
+ System.err.println("Please use only one of --start and --stop
options!");
return null;
}
- if (interval > 0) { //Set the interval if exists.
+ if (interval > 0) {
+ System.out.println("Setting watch interval to " + interval + "
ms");
watcher.setInterval(interval);
}
+ if (stop) {
+ System.out.println("Stopping watch");
+ watcher.stop();
+ }
+ if (urls != null && !urls.isEmpty()) {
+ if (remove) {
+ System.out.println("Removing watched urls");
+ watcher.remove(urls);
+ } else {
+ System.out.println("Adding watched urls");
+ watcher.add(urls);
+ }
+ }
+ if (start) {
+ System.out.println("Starting watch");
+ watcher.start();
+ }
if (list) { //List the watched bundles.
String format = "%-40s %6s %-80s";
@@ -68,21 +86,22 @@ public class Watch extends OsgiCommandSu
List<Bundle> bundleList = watcher.getBundlesByURL(url);
if (bundleList != null && bundleList.size() > 0) {
for (Bundle bundle : bundleList) {
- System.out.println(String.format(format, url,
bundle.getBundleId(), (String) bundle.getHeaders().get(Constants.BUNDLE_NAME)));
+ System.out.println(String.format(format, url,
bundle.getBundleId(), bundle.getHeaders().get(Constants.BUNDLE_NAME)));
}
} else {
System.out.println(String.format(format, url, "", ""));
}
}
- } else if (start) {
- watcher.start();
- } else if (stop) {
- watcher.stop();
- } else if (remove) {
- watcher.remove(urls);
} else {
- watcher.start();
- watcher.add(urls);
+ List<String> urls = watcher.getWatchURLs();
+ if (urls != null && !urls.isEmpty()) {
+ System.out.println("Watched urls:");
+ for (String url : watcher.getWatchURLs()) {
+ System.out.println(url);
+ }
+ } else {
+ System.out.println("No watched urls");
+ }
}
return null;
Modified:
karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/watch/BundleWatcher.java
URL:
http://svn.apache.org/viewvc/karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/watch/BundleWatcher.java?rev=1060242&r1=1060241&r2=1060242&view=diff
==============================================================================
---
karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/watch/BundleWatcher.java
(original)
+++
karaf/trunk/shell/dev/src/main/java/org/apache/karaf/shell/dev/watch/BundleWatcher.java
Tue Jan 18 08:54:31 2011
@@ -17,6 +17,20 @@
package org.apache.karaf.shell.dev.watch;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ops4j.pax.url.maven.commons.MavenConfiguration;
@@ -27,38 +41,26 @@ import org.ops4j.pax.url.mvn.internal.Pa
import org.ops4j.util.property.DictionaryPropertyResolver;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
-import org.osgi.framework.BundleReference;
-import org.osgi.framework.Constants;
+import org.osgi.framework.BundleListener;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
/**
* A Runnable singleton which watches at the defined location for bundle
updates.
*/
-public class BundleWatcher implements Runnable {
+public class BundleWatcher implements Runnable, BundleListener {
private static Log logger = LogFactory.getLog(BundleWatcher.class);
+ private BundleContext bundleContext;
private ConfigurationAdmin configurationAdmin;
- private Boolean running = false;
- private Long interval = 10000L;
- private List<String> watchURLs = new ArrayList<String>();
- private Map<Bundle, Long> lastModificationTimes = new HashMap<Bundle,
Long>();
+ private AtomicBoolean running = new AtomicBoolean(false);
+ private long interval = 1000L;
+ private List<String> watchURLs = new CopyOnWriteArrayList<String>();
+ private AtomicInteger counter = new AtomicInteger(0);
/**
@@ -67,24 +69,44 @@ public class BundleWatcher implements Ru
public BundleWatcher() {
}
+ public void bundleChanged(BundleEvent event) {
+ if (event.getType() == BundleEvent.INSTALLED
+ || event.getType() == BundleEvent.UNINSTALLED) {
+ counter.incrementAndGet();
+ }
+ }
+
public void run() {
if (logger.isDebugEnabled()) {
logger.debug("Bundle watcher thread started");
}
- while (running) {
- for (String bundleURL : watchURLs) {
- for (Bundle bundle : getBundlesByURL(bundleURL)) {
+ int oldCounter = -1;
+ Set<Bundle> watchedBundles = new HashSet<Bundle>();
+ while (running.get() && !watchURLs.isEmpty()) {
+ if (oldCounter != counter.get()) {
+ oldCounter = counter.get();
+ watchedBundles.clear();
+ for (String bundleURL : watchURLs) {
+ for (Bundle bundle : getBundlesByURL(bundleURL)) {
+ watchedBundles.add(bundle);
+ }
+ }
+ }
+ if (!watchedBundles.isEmpty()) {
+ File localRepository = getLocalRepository();
+ for (Bundle bundle : watchedBundles) {
try {
- Long lastModifiedTime =
getBundleLastModifiedTime(bundle);
- Long oldLastModifiedTime =
lastModificationTimes.get(bundle);
- if (!lastModifiedTime.equals(oldLastModifiedTime)) {
- String externalLocation =
getBundleExternalLocation(bundle);
- if (externalLocation != null) {
- File f = new File(externalLocation);
- InputStream is = new FileInputStream(f);
+ File location =
getBundleExternalLocation(localRepository, bundle);
+ if (location != null
+ && location.exists()
+ && location.lastModified() >
bundle.getLastModified())
+ {
+ InputStream is = new FileInputStream(location);
+ try {
+ System.out.println("[Watch] Updating watched
bundle: " + bundle.getSymbolicName() + " (" + bundle.getVersion() + ")");
bundle.update(is);
+ } finally {
is.close();
- lastModificationTimes.put(bundle,
lastModifiedTime);
}
}
} catch (IOException ex) {
@@ -96,8 +118,8 @@ public class BundleWatcher implements Ru
}
try {
Thread.sleep(interval);
- } catch (Exception ex) {
- running = false;
+ } catch (InterruptedException ex) {
+ running.set(false);
}
}
@@ -108,88 +130,69 @@ public class BundleWatcher implements Ru
/**
* Adds a Bundle URLs to the watch list.
- * @param urls
+ * @param url
*/
- public void add(String urls) {
- watchURLs.add(urls);
- for (Bundle bundle : getBundlesByURL(urls)) {
- lastModificationTimes.put(bundle,
getBundleLastModifiedTime(bundle));
+ public void add(String url) {
+ boolean shouldStart = running.get() && watchURLs.isEmpty();
+ if (!watchURLs.contains(url)) {
+ watchURLs.add(url);
+ counter.incrementAndGet();
+ }
+ if (shouldStart) {
+ Thread thread = new Thread(this);
+ thread.start();
}
}
/**
* Removes a bundle URLs from the watch list.
- * @param urls
+ * @param url
*/
- public void remove(String urls) {
- watchURLs.remove(urls);
- for (Bundle bundle : getBundlesByURL(urls)) {
- lastModificationTimes.remove(bundle);
- }
+ public void remove(String url) {
+ watchURLs.remove(url);
+ counter.incrementAndGet();
}
/**
- * Returns the last modification time of the bundle artifact as Long.
+ * Returns the location of the Bundle inside the local maven repository.
* @param bundle
* @return
*/
- private Long getBundleLastModifiedTime(Bundle bundle) {
- Long lastModificationTime = 0L;
- String bundleExternalLocation = getBundleExternalLocation(bundle);
- if (bundleExternalLocation != null) {
- File bundleFile = new File(bundleExternalLocation);
- lastModificationTime = bundleFile.lastModified();
+ public File getBundleExternalLocation(File localRepository, Bundle bundle)
{
+ try {
+ Parser p = new Parser(bundle.getLocation().substring(4));
+ return new File(localRepository.getPath() + File.separator +
p.getArtifactPath());
+ } catch (MalformedURLException e) {
+ logger.error("Could not parse artifact path for bundle" +
bundle.getSymbolicName(), e);
}
- return lastModificationTime;
+ return null;
}
- /**
- * Returns the location of the Bundle inside the local maven repository.
- * @param bundle
- * @return
- */
- public String getBundleExternalLocation(Bundle bundle) {
- Parser p = null;
- String bundleExternalLocation = null;
- String localRepository = null;
-
- //Attempt to retrieve local repository location from MavenConfiguration
+ public File getLocalRepository() {
+ // Attempt to retrieve local repository location from
MavenConfiguration
MavenConfiguration configuration = retrieveMavenConfiguration();
if (configuration != null) {
MavenRepositoryURL localRepositoryURL =
configuration.getLocalRepository();
if (localRepositoryURL != null) {
- localRepository =
localRepositoryURL.getFile().getAbsolutePath();
+ return localRepositoryURL.getFile().getAbsoluteFile();
}
}
-
- //If local repository not found assume default.
- if (localRepository == null) {
- localRepository = System.getProperty("user.home") + File.separator
+ ".m2" + File.separator + "repository";
- }
-
- try {
- p = new Parser(bundle.getLocation().substring(4));
- bundleExternalLocation = localRepository + File.separator +
p.getArtifactPath();
- } catch (MalformedURLException e) {
- logger.error("Could not parse artifact path for bundle" +
bundle.getSymbolicName(), e);
- }
- return bundleExternalLocation;
+ // If local repository not found assume default.
+ String localRepo = System.getProperty("user.home") + File.separator +
".m2" + File.separator + "repository";
+ return new File(localRepo).getAbsoluteFile();
}
-
- public MavenConfiguration retrieveMavenConfiguration() {
- MavenConfiguration mavenConfiguration=null;
-
+ protected MavenConfiguration retrieveMavenConfiguration() {
+ MavenConfiguration mavenConfiguration = null;
try {
Configuration configuration =
configurationAdmin.getConfiguration(ServiceConstants.PID);
- if(configuration != null){
- Dictionary dictonary = configuration.getProperties();
- if(dictonary != null) {
- DictionaryPropertyResolver resolver = new
DictionaryPropertyResolver(dictonary);
- mavenConfiguration = new
MavenConfigurationImpl(resolver,ServiceConstants.PID);
- }
+ if (configuration != null) {
+ Dictionary dictonary = configuration.getProperties();
+ if (dictonary != null) {
+ DictionaryPropertyResolver resolver = new
DictionaryPropertyResolver(dictonary);
+ mavenConfiguration = new MavenConfigurationImpl(resolver,
ServiceConstants.PID);
+ }
}
-
} catch (IOException e) {
logger.error("Error retrieving maven configuration",e);
}
@@ -202,7 +205,6 @@ public class BundleWatcher implements Ru
* @return
*/
public List<Bundle> getBundlesByURL(String url) {
- BundleContext bundleContext = ((BundleReference)
getClass().getClassLoader()).getBundle().getBundleContext();
List<Bundle> bundleList = new ArrayList<Bundle>();
try {
Long id = Long.parseLong(url);
@@ -211,10 +213,9 @@ public class BundleWatcher implements Ru
bundleList.add(bundle);
}
} catch (NumberFormatException e) {
-
for (int i = 0; i < bundleContext.getBundles().length; i++) {
Bundle bundle = bundleContext.getBundles()[i];
- if (wildCardMatch(bundle.getLocation(), url)) {
+ if (isMavenSnapshotUrl(bundle.getLocation()) &&
wildCardMatch(bundle.getLocation(), url)) {
bundleList.add(bundle);
}
}
@@ -222,8 +223,12 @@ public class BundleWatcher implements Ru
return bundleList;
}
+ protected boolean isMavenSnapshotUrl(String url) {
+ return url.startsWith("mvn:") && url.contains("-SNAPSHOT");
+ }
+
/**
- * Matches text using a pattern containing wildchards.
+ * Matches text using a pattern containing wildcards.
*
* @param text
* @param pattern
@@ -247,10 +252,11 @@ public class BundleWatcher implements Ru
public void start() {
- if (!running) {
- Thread thread = new Thread(this);
- setRunning(true);
- thread.start();
+ if (running.compareAndSet(false, true)) {
+ if (!watchURLs.isEmpty()) {
+ Thread thread = new Thread(this);
+ thread.start();
+ }
}
}
@@ -258,7 +264,7 @@ public class BundleWatcher implements Ru
* Stops the execution of the thread and releases the singleton instance
*/
public void stop() {
- setRunning(false);
+ running.set(false);
}
public ConfigurationAdmin getConfigurationAdmin() {
@@ -269,6 +275,14 @@ public class BundleWatcher implements Ru
this.configurationAdmin = configurationAdmin;
}
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
public List<String> getWatchURLs() {
return watchURLs;
}
@@ -277,19 +291,16 @@ public class BundleWatcher implements Ru
this.watchURLs = watchURLs;
}
- public Long getInterval() {
+ public long getInterval() {
return interval;
}
- public void setInterval(Long interval) {
+ public void setInterval(long interval) {
this.interval = interval;
}
- public Boolean isRunning() {
- return running;
+ public boolean isRunning() {
+ return running.get();
}
- public void setRunning(Boolean running) {
- this.running = running;
- }
}
Modified:
karaf/trunk/shell/dev/src/main/resources/OSGI-INF/blueprint/shell-dev.xml
URL:
http://svn.apache.org/viewvc/karaf/trunk/shell/dev/src/main/resources/OSGI-INF/blueprint/shell-dev.xml?rev=1060242&r1=1060241&r2=1060242&view=diff
==============================================================================
--- karaf/trunk/shell/dev/src/main/resources/OSGI-INF/blueprint/shell-dev.xml
(original)
+++ karaf/trunk/shell/dev/src/main/resources/OSGI-INF/blueprint/shell-dev.xml
Tue Jan 18 08:54:31 2011
@@ -47,7 +47,8 @@
<!-- Referenace to the Configuration Admin Service -->
<reference id="configurationAdmin"
interface="org.osgi.service.cm.ConfigurationAdmin"/>
- <bean id="watcher" class="org.apache.karaf.shell.dev.watch.BundleWatcher">
+ <bean id="watcher" class="org.apache.karaf.shell.dev.watch.BundleWatcher"
init-method="start" destroy-method="stop">
+ <property name="bundleContext" ref="blueprintBundleContext"/>
<property name="configurationAdmin" ref="configurationAdmin"/>
</bean>
Added:
karaf/trunk/shell/dev/src/main/resources/org/apache/karaf/shell/dev/watch.txt
URL:
http://svn.apache.org/viewvc/karaf/trunk/shell/dev/src/main/resources/org/apache/karaf/shell/dev/watch.txt?rev=1060242&view=auto
==============================================================================
---
karaf/trunk/shell/dev/src/main/resources/org/apache/karaf/shell/dev/watch.txt
(added)
+++
karaf/trunk/shell/dev/src/main/resources/org/apache/karaf/shell/dev/watch.txt
Tue Jan 18 08:54:31 2011
@@ -0,0 +1,3 @@
+The watch command can be used to help at developement time. It allows you to
configure a set of URLs that will be monitored. All bundles location matching
the given URL will be automatically updated. This avoids the need for manually
updating the bundles or even copying the bundle to the system folder if needed.
Note that only maven based urls and maven snapshots will actually be updated
automatically, so if you run
+ > dev:watch *
+It will actually monitor all bundles that have a location matching mvn:* that
have '-SNAPSHOT' in their url.