You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by an...@apache.org on 2013/10/22 23:16:48 UTC
svn commit: r1534794 - in /ace/trunk/org.apache.ace.deployment:
src/org/apache/ace/deployment/provider/
src/org/apache/ace/deployment/provider/filebased/
src/org/apache/ace/deployment/provider/repositorybased/
src/org/apache/ace/deployment/servlet/ src...
Author: angelos
Date: Tue Oct 22 21:16:47 2013
New Revision: 1534794
URL: http://svn.apache.org/r1534794
Log:
ACE-388 Deployment can now result in an OverloadedException, which in turn causes a "Retry-After" header to be set.
Added:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/OverloadedException.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/OverloadedFilter.java
ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderConcurrencyTest.java
Modified:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/DeploymentProvider.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/filebased/FileBasedProvider.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/StreamGeneratorImpl.java
ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/MockDeploymentRepository.java
ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java
ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderTest.java
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/DeploymentProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/DeploymentProvider.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/DeploymentProvider.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/DeploymentProvider.java Tue Oct 22 21:16:47 2013
@@ -33,9 +33,10 @@ public interface DeploymentProvider {
*
* @return a collection of bundledata. If there are no bundles in this version, return an empty list
* @throws IllegalArgumentException if the target or version do not exist
+ * @throws OverloadedException if the provider is overloaded
* @throws java.io.IOException If an IOException occurs.
*/
- public List<ArtifactData> getBundleData(String targetId, String version) throws IllegalArgumentException, IOException;
+ public List<ArtifactData> getBundleData(String targetId, String version) throws OverloadedException, IllegalArgumentException, IOException;
/**
* This data can be used to generate a fix package. It gives the differences between the versionFrom and versionTo.
@@ -50,10 +51,11 @@ public interface DeploymentProvider {
*
* @return a list of bundles.
* @throws IllegalArgumentException if the target, the versionFrom or versionTo do no exist
+ * @throws OverloadedException if the provider is overloaded
* @throws java.io.IOException If an IOException occurs.
*/
- public List<ArtifactData> getBundleData(String targetId, String versionFrom, String versionTo) throws IllegalArgumentException, IOException;
+ public List<ArtifactData> getBundleData(String targetId, String versionFrom, String versionTo) throws OverloadedException, IllegalArgumentException, IOException;
/**
* Returns a list of versions for a specific target. The list is sorted in
@@ -65,6 +67,7 @@ public interface DeploymentProvider {
* return an empty List.
* If the target doesn't exist, an IllegalArgumentException is thrown
* @throws java.io.IOException If an IOException occurs.
+ * @throws OverloadedException if the provider is overloaded
*/
- public List<String> getVersions(String targetId) throws IllegalArgumentException, IOException;
+ public List<String> getVersions(String targetId) throws OverloadedException, IllegalArgumentException, IOException;
}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/OverloadedException.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/OverloadedException.java?rev=1534794&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/OverloadedException.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/OverloadedException.java Tue Oct 22 21:16:47 2013
@@ -0,0 +1,50 @@
+/*
+ * 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.ace.deployment.provider;
+
+/**
+ * Exception that indicates that the deployment provider is overloaded.
+ * Callers that receive this exception should
+ */
+public class OverloadedException extends RuntimeException {
+
+ private static final long serialVersionUID = 915400242733422258L;
+
+ private final int m_backoffTime;
+
+ /**
+ * Exception that indicates that the caller should try again after at least the specified backoffTime
+ *
+ * @param message the error message
+ * @param backoffTime the requested backoff time in seconds
+ */
+ public OverloadedException(String message, int backoffTime) {
+ super(message);
+ m_backoffTime = backoffTime;
+ }
+
+ /**
+ * Returns the time to "back off" from trying again.
+ *
+ * @return a back off time, in seconds.
+ */
+ public int getBackoffTime() {
+ return m_backoffTime;
+ }
+}
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/filebased/FileBasedProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/filebased/FileBasedProvider.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/filebased/FileBasedProvider.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/filebased/FileBasedProvider.java Tue Oct 22 21:16:47 2013
@@ -34,12 +34,14 @@ import java.util.Dictionary;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.apache.ace.deployment.provider.ArtifactData;
import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.provider.OverloadedException;
import org.apache.ace.deployment.provider.impl.ArtifactDataImpl;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
@@ -59,17 +61,160 @@ public class FileBasedProvider implement
private static final String DIRECTORY_NAME = "BaseDirectoryName";
/** Fallback directory for all targets that have no specific versions. Defaults to BaseDirectoryName if not specified. */
private static final String DEFAULT_DIRECTORY_NAME = "DefaultDirectoryName";
+ /** Configuration key for the number of concurrent users */
+ private static final String MAXIMUM_NUMBER_OF_USERS = "MaximumNumberOfUsers";
private static final int OSGI_R4_MANIFEST_VERSION = 2;
private volatile File m_baseDirectory;
private volatile File m_defaultDirectory;
private volatile LogService m_log;
private final Semaphore m_disk = new Semaphore(1, true);
+
+ private final AtomicInteger m_usageCounter = new AtomicInteger();
+ /** Maximum number of concurrent users. Value 0 is used for unlimited users. */
+ private int m_maximumNumberOfUsers = 0;
+ /** The default backoff time for each new user over the limit */
+ private static final int BACKOFF_TIME_PER_USER = 5;
/**
* Get the bundle data from the bundles in the <data dir>/<target>/<version> directory It reads the manifest from all the
* .jar files in that directory. If the manifest cannot be found, This method can only parse OSGi R4 bundles
*/
- public List<ArtifactData> getBundleData(String targetId, String version) throws IllegalArgumentException {
+ public List<ArtifactData> getBundleData(String targetId, String version) throws OverloadedException, IllegalArgumentException {
+ try {
+ int concurrentUsers = m_usageCounter.incrementAndGet();
+ if (m_maximumNumberOfUsers != 0 && m_maximumNumberOfUsers < concurrentUsers) {
+ throw new OverloadedException("Too many users, maximum allowed = " + m_maximumNumberOfUsers + ", current = " + concurrentUsers, (concurrentUsers - m_maximumNumberOfUsers) * BACKOFF_TIME_PER_USER);
+ }
+ return internalGetBundleData(targetId, version);
+ } finally {
+ m_usageCounter.getAndDecrement();
+ }
+
+ }
+
+ /**
+ * Version folder and requested version do not always match (see implementation of getVersions, which uses Versions.parseVersion to allow different styles)
+ * like 1 instead of 1.0.0 and alike.
+ * So we need to do some crawling to map them.
+ *
+ * @param targetDirectory store directory
+ * @param version that has been requested.
+ *
+ * @return the matching folder.
+ *
+ * @throws IllegalArgumentException if no matching folder has been found. If this happens something is weirdly wrong.
+ */
+ private File findMatchingVersionDirectory(File targetDirectory, String version) {
+ // first try the direct way:
+ File directTry = new File(targetDirectory, version);
+ if ((directTry != null) && directTry.isDirectory()) {
+ return directTry;
+ }
+ // otherwise try to find it:
+ Version requestedVersion;
+ try {
+ requestedVersion = Version.parseVersion(version);
+ }
+ catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("Requested version " + version + " has no matching folder in store: " + targetDirectory.getAbsolutePath());
+ }
+
+ File[] files = targetDirectory.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ File possibleVersionDirectory = files[i];
+ if (possibleVersionDirectory.isDirectory()) {
+ // ok, it is a directory. Now see if it is a version
+ try {
+ Version foundVersion = Version.parseVersion(possibleVersionDirectory.getName());
+ // no exception, but is could still be an empty version
+ if ((requestedVersion != null) && requestedVersion.equals(foundVersion)) {
+ return new File(targetDirectory, possibleVersionDirectory.getName());
+ }
+ }
+ catch (IllegalArgumentException iae) {
+ // dont' care at this point.
+ }
+ }
+ }
+ throw new IllegalArgumentException("Requested version " + version + " has no matching folder in store: " + targetDirectory.getAbsolutePath());
+ }
+
+ public List<ArtifactData> getBundleData(String targetId, String versionFrom, String versionTo) throws OverloadedException, IllegalArgumentException {
+ try {
+ int concurrentUsers = m_usageCounter.incrementAndGet();
+ if (m_maximumNumberOfUsers != 0 && m_maximumNumberOfUsers < concurrentUsers) {
+ throw new OverloadedException("Too many users, maximum allowed = " + m_maximumNumberOfUsers + ", current = " + concurrentUsers, (concurrentUsers - m_maximumNumberOfUsers) * BACKOFF_TIME_PER_USER);
+ }
+ List<ArtifactData> dataVersionFrom = internalGetBundleData(targetId, versionFrom);
+ List<ArtifactData> dataVersionTo = internalGetBundleData(targetId, versionTo);
+
+ Iterator<ArtifactData> it = dataVersionTo.iterator();
+ while (it.hasNext()) {
+ ArtifactDataImpl bundleDataVersionTo = (ArtifactDataImpl) it.next();
+ // see if there was previously a version of this bundle.
+ ArtifactData bundleDataVersionFrom = getBundleData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
+ bundleDataVersionTo.setChanged(!bundleDataVersionTo.equals(bundleDataVersionFrom));
+ }
+ return dataVersionTo;
+ } finally {
+ m_usageCounter.getAndDecrement();
+ }
+ }
+
+ /**
+ * Check for the existence of bundledata in the collection for a bundle with the given symbolic name
+ *
+ * @param symbolicName
+ */
+ private ArtifactData getBundleData(String symbolicName, Collection<ArtifactData> data) {
+ Iterator<ArtifactData> it = data.iterator();
+ while (it.hasNext()) {
+ ArtifactData bundle = it.next();
+ if (bundle.getSymbolicName().equals(symbolicName)) {
+ return bundle;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Look in the baseDirectory for the specified target. If it exists, get the list of directories in there and check if they
+ * conform to the <code>org.osgi.framework.Version</code> format. If it does, it will be in the list of versions that are
+ * returned. If there are no valid versions, return an empty list. If the target cannot be found, an
+ * IllegalArgumentException is thrown. The list will be sorted on version.
+ */
+ @SuppressWarnings("unchecked")
+ public List<String> getVersions(String targetId) throws OverloadedException, IllegalArgumentException {
+ try {
+ int concurrentUsers = m_usageCounter.incrementAndGet();
+ if (m_maximumNumberOfUsers != 0 && m_maximumNumberOfUsers < concurrentUsers) {
+ throw new OverloadedException("Too many users, maximum allowed = " + m_maximumNumberOfUsers + ", current = " + concurrentUsers, (concurrentUsers - m_maximumNumberOfUsers) * BACKOFF_TIME_PER_USER);
+ }
+ List<Version> versionList = new ArrayList<Version>();
+ File targetDirectory = new File(m_baseDirectory.getAbsolutePath(), targetId);
+ if (targetDirectory.isDirectory()) {
+ getVersions(targetId, versionList, targetDirectory);
+ }
+ else {
+ // try the default
+ getVersions(targetId, versionList, m_defaultDirectory);
+ }
+
+ // now sort the list of versions and convert all values to strings.
+ Collections.sort(versionList);
+ List<String> stringVersionList = new ArrayList<String>();
+ Iterator<Version> it = versionList.iterator();
+ while (it.hasNext()) {
+ String version = (it.next()).toString();
+ stringVersionList.add(version);
+ }
+ return stringVersionList;
+ } finally {
+ m_usageCounter.getAndDecrement();
+ }
+ }
+
+ private List<ArtifactData> internalGetBundleData(String targetId, String version) throws OverloadedException, IllegalArgumentException {
List<String> versions = getVersions(targetId);
if (!versions.contains(version)) {
throw new IllegalArgumentException("Unknown version " + version + " requested");
@@ -197,113 +342,7 @@ public class FileBasedProvider implement
return bundleData;
}
-
- /**
- * Version folder and requested version do not always match (see implementation of getVersions, which uses Versions.parseVersion to allow different styles)
- * like 1 instead of 1.0.0 and alike.
- * So we need to do some crawling to map them.
- *
- * @param targetDirectory store directory
- * @param version that has been requested.
- *
- * @return the matching folder.
- *
- * @throws IllegalArgumentException if no matching folder has been found. If this happens something is weirdly wrong.
- */
- private File findMatchingVersionDirectory(File targetDirectory, String version) {
- // first try the direct way:
- File directTry = new File(targetDirectory, version);
- if ((directTry != null) && directTry.isDirectory()) {
- return directTry;
- }
- // otherwise try to find it:
- Version requestedVersion;
- try {
- requestedVersion = Version.parseVersion(version);
- }
- catch (IllegalArgumentException iae) {
- throw new IllegalArgumentException("Requested version " + version + " has no matching folder in store: " + targetDirectory.getAbsolutePath());
- }
-
- File[] files = targetDirectory.listFiles();
- for (int i = 0; i < files.length; i++) {
- File possibleVersionDirectory = files[i];
- if (possibleVersionDirectory.isDirectory()) {
- // ok, it is a directory. Now see if it is a version
- try {
- Version foundVersion = Version.parseVersion(possibleVersionDirectory.getName());
- // no exception, but is could still be an empty version
- if ((requestedVersion != null) && requestedVersion.equals(foundVersion)) {
- return new File(targetDirectory, possibleVersionDirectory.getName());
- }
- }
- catch (IllegalArgumentException iae) {
- // dont' care at this point.
- }
- }
- }
- throw new IllegalArgumentException("Requested version " + version + " has no matching folder in store: " + targetDirectory.getAbsolutePath());
- }
-
- public List<ArtifactData> getBundleData(String targetId, String versionFrom, String versionTo) throws IllegalArgumentException {
- List<ArtifactData> dataVersionFrom = getBundleData(targetId, versionFrom);
- List<ArtifactData> dataVersionTo = getBundleData(targetId, versionTo);
-
- Iterator<ArtifactData> it = dataVersionTo.iterator();
- while (it.hasNext()) {
- ArtifactDataImpl bundleDataVersionTo = (ArtifactDataImpl) it.next();
- // see if there was previously a version of this bundle.
- ArtifactData bundleDataVersionFrom = getBundleData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
- bundleDataVersionTo.setChanged(!bundleDataVersionTo.equals(bundleDataVersionFrom));
- }
- return dataVersionTo;
- }
-
- /**
- * Check for the existence of bundledata in the collection for a bundle with the given symbolic name
- *
- * @param symbolicName
- */
- private ArtifactData getBundleData(String symbolicName, Collection<ArtifactData> data) {
- Iterator<ArtifactData> it = data.iterator();
- while (it.hasNext()) {
- ArtifactData bundle = it.next();
- if (bundle.getSymbolicName().equals(symbolicName)) {
- return bundle;
- }
- }
- return null;
- }
-
- /**
- * Look in the baseDirectory for the specified target. If it exists, get the list of directories in there and check if they
- * conform to the <code>org.osgi.framework.Version</code> format. If it does, it will be in the list of versions that are
- * returned. If there are no valid versions, return an empty list. If the target cannot be found, an
- * IllegalArgumentException is thrown. The list will be sorted on version.
- */
- @SuppressWarnings("unchecked")
- public List<String> getVersions(String targetId) throws IllegalArgumentException {
- List<Version> versionList = new ArrayList<Version>();
- File targetDirectory = new File(m_baseDirectory.getAbsolutePath(), targetId);
- if (targetDirectory.isDirectory()) {
- getVersions(targetId, versionList, targetDirectory);
- }
- else {
- // try the default
- getVersions(targetId, versionList, m_defaultDirectory);
- }
-
- // now sort the list of versions and convert all values to strings.
- Collections.sort(versionList);
- List<String> stringVersionList = new ArrayList<String>();
- Iterator<Version> it = versionList.iterator();
- while (it.hasNext()) {
- String version = (it.next()).toString();
- stringVersionList.add(version);
- }
- return stringVersionList;
- }
-
+
/**
*
* @param targetId ID that requested versions
@@ -339,6 +378,11 @@ public class FileBasedProvider implement
*/
public void updated(Dictionary settings) throws ConfigurationException {
if (settings != null) {
+ String maximumNumberOfUsers = (String) settings.get(MAXIMUM_NUMBER_OF_USERS);
+ if (maximumNumberOfUsers != null) {
+ m_maximumNumberOfUsers = Integer.parseInt(maximumNumberOfUsers);
+ }
+
String baseDirectoryName = getNotNull(settings, DIRECTORY_NAME, "The base directory cannot be null");
File baseDirectory = new File(baseDirectoryName);
if (!baseDirectory.exists() || !baseDirectory.isDirectory()) {
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java Tue Oct 22 21:16:47 2013
@@ -32,15 +32,17 @@ import java.util.Dictionary;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import javax.xml.parsers.SAXParserFactory;
+import org.apache.ace.connectionfactory.ConnectionFactory;
import org.apache.ace.deployment.provider.ArtifactData;
import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.provider.OverloadedException;
import org.apache.ace.deployment.provider.impl.ArtifactDataImpl;
import org.apache.ace.deployment.provider.repositorybased.BaseRepositoryHandler.XmlDeploymentArtifact;
-import org.apache.ace.connectionfactory.ConnectionFactory;
import org.apache.ace.range.RangeIterator;
import org.apache.ace.repository.Repository;
import org.apache.ace.repository.ext.BackupRepository;
@@ -97,8 +99,12 @@ public class RepositoryBasedProvider imp
public static final String KEY_RESOURCE_PROCESSOR_PID = "Deployment-ProvidesResourceProcessor";
public static final String MIMETYPE = "application/vnd.osgi.bundle";
-
+ /**
+ * Key, intended for configurations that specifies the maximum number of concurrent users for this repository provider.
+ */
+ private static final String MAXIMUM_NUMBER_OF_USERS = "MaximumNumberOfUsers";
+
private volatile LogService m_log;
/** This variable is volatile since it can be changed by the Updated() method. */
@@ -114,143 +120,169 @@ public class RepositoryBasedProvider imp
private final SAXParserFactory m_saxParserFactory;
private final Map<String,List<String>> m_cachedVersionLists;
+ private final AtomicInteger m_usageCounter = new AtomicInteger();
+ /** Maximum number of concurrent users. Values <= 0 are used for unlimited users. */
+ private int m_maximumNumberOfUsers = 0;
+ /** The default backoff time for each new user over the limit */
+ private static final int BACKOFF_TIME_PER_USER = 5;
+
public RepositoryBasedProvider() {
m_saxParserFactory = SAXParserFactory.newInstance();
m_cachedVersionLists = new LRUMap<String, List<String>>();
}
- public List<ArtifactData> getBundleData(String targetId, String version) throws IllegalArgumentException, IOException {
+ public List<ArtifactData> getBundleData(String targetId, String version) throws OverloadedException, IllegalArgumentException, IOException {
return getBundleData(targetId, null, version);
}
- public List<ArtifactData> getBundleData(String targetId, String versionFrom, String versionTo) throws IllegalArgumentException, IOException {
+ public List<ArtifactData> getBundleData(String targetId, String versionFrom, String versionTo) throws OverloadedException, IllegalArgumentException, IOException {
try {
- if (versionFrom != null) {
- Version.parseVersion(versionFrom);
+ int concurrentUsers = m_usageCounter.incrementAndGet();
+ if (m_maximumNumberOfUsers != 0 && m_maximumNumberOfUsers < concurrentUsers) {
+ throw new OverloadedException("Too many users, maximum allowed = " + m_maximumNumberOfUsers + ", current = " + concurrentUsers, (concurrentUsers - m_maximumNumberOfUsers) * BACKOFF_TIME_PER_USER);
}
- Version.parseVersion(versionTo);
- }
- catch (NumberFormatException nfe) {
- throw new IllegalArgumentException(nfe);
- }
-
- InputStream input = null;
- List<ArtifactData> dataVersionTo = null;
- List<ArtifactData> dataVersionFrom = null;
- List<XmlDeploymentArtifact>[] pairs = null;
- try {
- // ACE-240: do NOT allow local/remote repositories to be empty. If we're
- // asking for real artifacts, it means we must have a repository...
- input = getRepositoryStream(true /* fail */);
- if (versionFrom == null) {
- pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionTo });
+ try {
+ if (versionFrom != null) {
+ Version.parseVersion(versionFrom);
+ }
+ Version.parseVersion(versionTo);
}
- else {
- pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionFrom, versionTo });
+ catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException(nfe);
}
- }
- catch (IOException ioe) {
- m_log.log(LogService.LOG_WARNING, "Problem parsing source version.", ioe);
- throw ioe;
- }
- finally {
- if (input != null) {
- try {
- input.close();
+
+ InputStream input = null;
+ List<ArtifactData> dataVersionTo = null;
+ List<ArtifactData> dataVersionFrom = null;
+
+ List<XmlDeploymentArtifact>[] pairs = null;
+ try {
+ // ACE-240: do NOT allow local/remote repositories to be empty. If we're
+ // asking for real artifacts, it means we must have a repository...
+ input = getRepositoryStream(true /* fail */);
+ if (versionFrom == null) {
+ pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionTo });
}
- catch (IOException e) {
- m_log.log(LogService.LOG_DEBUG, "Error closing stream", e);
+ else {
+ pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionFrom, versionTo });
}
}
- }
-
- if ((pairs != null) && (pairs.length > 1)) {
- dataVersionFrom = getAllArtifactData(pairs[0]);
- dataVersionTo = getAllArtifactData(pairs[1]);
- Iterator<ArtifactData> it = dataVersionTo.iterator();
- while (it.hasNext()) {
- ArtifactDataImpl bundleDataVersionTo = (ArtifactDataImpl) it.next();
- // see if there was previously a version of this bundle, and update the 'changed' property accordingly.
- if (bundleDataVersionTo.isBundle()) {
- ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
- bundleDataVersionTo.setChanged(!bundleDataVersionTo.equals(bundleDataVersionFrom));
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Problem parsing source version.", ioe);
+ throw ioe;
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_DEBUG, "Error closing stream", e);
+ }
}
- else {
- ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getUrl(), dataVersionFrom);
- bundleDataVersionTo.setChanged(bundleDataVersionFrom == null);
+ }
+
+ if ((pairs != null) && (pairs.length > 1)) {
+ dataVersionFrom = getAllArtifactData(pairs[0]);
+ dataVersionTo = getAllArtifactData(pairs[1]);
+ Iterator<ArtifactData> it = dataVersionTo.iterator();
+ while (it.hasNext()) {
+ ArtifactDataImpl bundleDataVersionTo = (ArtifactDataImpl) it.next();
+ // see if there was previously a version of this bundle, and update the 'changed' property accordingly.
+ if (bundleDataVersionTo.isBundle()) {
+ ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
+ bundleDataVersionTo.setChanged(!bundleDataVersionTo.equals(bundleDataVersionFrom));
+ }
+ else {
+ ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getUrl(), dataVersionFrom);
+ bundleDataVersionTo.setChanged(bundleDataVersionFrom == null);
+ }
}
}
+ else {
+ dataVersionTo = getAllArtifactData(pairs[0]);
+ }
+
+ return dataVersionTo != null ? dataVersionTo : new ArrayList<ArtifactData>();
}
- else {
- dataVersionTo = getAllArtifactData(pairs[0]);
+ finally {
+ m_usageCounter.getAndDecrement();
}
-
- return dataVersionTo != null ? dataVersionTo : new ArrayList<ArtifactData>();
}
@SuppressWarnings("unchecked")
- public List<String> getVersions(String targetId) throws IllegalArgumentException, IOException {
- // check if cache is up to date
- if (isCacheUpToDate()) {
- List<String> result = m_cachedVersionLists.get(targetId);
- if (result != null) {
- return result;
- }
- }
- else {
- m_cachedVersionLists.clear();
- }
-
- List<String> stringVersionList = new ArrayList<String>();
- InputStream input = null;
-
+ public List<String> getVersions(String targetId) throws OverloadedException, IllegalArgumentException, IOException {
try {
- // ACE-240: allow local/remote repositories to be empty; as the target
- // might be new & unregistered, it can have no repository yet...
- input = getRepositoryStream(false /* fail */);
- List<Version> versionList;
- if (input == null) {
- versionList = Collections.EMPTY_LIST;
+ int concurrentUsers = m_usageCounter.incrementAndGet();
+ if (m_maximumNumberOfUsers != 0 && m_maximumNumberOfUsers < concurrentUsers) {
+ throw new OverloadedException("Too many users, maximum allowed = " + m_maximumNumberOfUsers + ", current = " + concurrentUsers, (concurrentUsers - m_maximumNumberOfUsers) * BACKOFF_TIME_PER_USER);
}
- else {
- versionList = getAvailableVersions(input, targetId);
- }
- if (versionList.isEmpty()) {
- m_log.log(LogService.LOG_DEBUG, "No versions found for target: " + targetId);
+
+ // check if cache is up to date
+ if (isCacheUpToDate()) {
+ List<String> result = m_cachedVersionLists.get(targetId);
+ if (result != null) {
+ return result;
+ }
}
else {
- // now sort the list of versions and convert all values to strings.
- Collections.sort(versionList);
- Iterator<Version> it = versionList.iterator();
- while (it.hasNext()) {
- String version = (it.next()).toString();
- stringVersionList.add(version);
- }
+ m_cachedVersionLists.clear();
}
- }
- catch (IllegalArgumentException iae) {
- // just move on.
- }
- catch (IOException ioe) {
- m_log.log(LogService.LOG_DEBUG, "Problem parsing DeploymentRepository", ioe);
- throw ioe;
- }
- finally {
- if (input != null) {
- try {
- input.close();
+
+ List<String> stringVersionList = new ArrayList<String>();
+ InputStream input = null;
+
+ try {
+ // ACE-240: allow local/remote repositories to be empty; as the target
+ // might be new & unregistered, it can have no repository yet...
+ input = getRepositoryStream(false /* fail */);
+ List<Version> versionList;
+ if (input == null) {
+ versionList = Collections.EMPTY_LIST;
+ }
+ else {
+ versionList = getAvailableVersions(input, targetId);
}
- catch (IOException e) {
- m_log.log(LogService.LOG_DEBUG, "Error closing stream", e);
+ if (versionList.isEmpty()) {
+ m_log.log(LogService.LOG_DEBUG, "No versions found for target: " + targetId);
+ }
+ else {
+ // now sort the list of versions and convert all values to strings.
+ Collections.sort(versionList);
+ Iterator<Version> it = versionList.iterator();
+ while (it.hasNext()) {
+ String version = (it.next()).toString();
+ stringVersionList.add(version);
+ }
+ }
+ }
+ catch (IllegalArgumentException iae) {
+ // just move on.
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_DEBUG, "Problem parsing DeploymentRepository", ioe);
+ throw ioe;
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_DEBUG, "Error closing stream", e);
+ }
}
}
- }
- m_log.log(LogService.LOG_DEBUG, "Cache added for " + targetId);
+ m_log.log(LogService.LOG_DEBUG, "Cache added for " + targetId);
- m_cachedVersionLists.put(targetId, stringVersionList);
- return stringVersionList;
+ m_cachedVersionLists.put(targetId, stringVersionList);
+ return stringVersionList;
+ }
+ finally {
+ m_usageCounter.getAndDecrement();
+ }
}
/**
@@ -446,7 +478,17 @@ public class RepositoryBasedProvider imp
String url = getNotNull(settings, URL, "DeploymentRepository URL not configured.");
String name = getNotNull(settings, NAME, "RepositoryName not configured.");
String customer = getNotNull(settings, CUSTOMER, "RepositoryCustomer not configured.");
-
+ String maximumNumberOfUsers = (String) settings.get(MAXIMUM_NUMBER_OF_USERS);
+
+ if (maximumNumberOfUsers != null) {
+ try {
+ m_maximumNumberOfUsers = Integer.parseInt(maximumNumberOfUsers);
+ }
+ catch (NumberFormatException nfe) {
+ throw new ConfigurationException(MAXIMUM_NUMBER_OF_USERS, maximumNumberOfUsers + " is not a valid value for the maximum number of concurrent users.");
+ }
+ }
+
// create the remote repository and set it.
try {
BackupRepository backup = new FilebasedBackupRepository(File.createTempFile("currentrepository", null), File.createTempFile("backuprepository", null));
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java Tue Oct 22 21:16:47 2013
@@ -18,6 +18,9 @@
*/
package org.apache.ace.deployment.servlet;
+import java.util.Properties;
+
+import javax.servlet.Filter;
import javax.servlet.Servlet;
import org.apache.ace.connectionfactory.ConnectionFactory;
@@ -51,6 +54,13 @@ public class Activator extends Dependenc
.add(createServiceDependency().setService(ConnectionFactory.class).setRequired(true))
.add(createServiceDependency().setService(LogService.class).setRequired(false))
);
+
+ Properties props = new Properties();
+ props.put("pattern", "/*");
+ manager.add(createComponent()
+ .setInterface(Filter.class.getName(), null)
+ .setImplementation(OverloadedFilter.class)
+ );
}
@Override
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/DeploymentServlet.java Tue Oct 22 21:16:47 2013
@@ -38,6 +38,7 @@ import org.apache.ace.authentication.api
import org.apache.ace.deployment.processor.DeploymentProcessor;
import org.apache.ace.deployment.provider.ArtifactData;
import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.provider.OverloadedException;
import org.apache.ace.deployment.streamgenerator.StreamGenerator;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
@@ -91,7 +92,7 @@ public class DeploymentServlet extends H
* <code>HttpServletResponse.SC_OK</code> - If all went fine
*/
@Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
try {
String[] pathElements = verifyAndGetPathElements(request.getPathInfo());
String targetID = pathElements[1];
@@ -109,6 +110,9 @@ public class DeploymentServlet extends H
m_log.log(LogService.LOG_WARNING, e.getMessage(), e);
e.handleAsHttpError(response);
}
+ catch (OverloadedException oe) {
+ throw new ServletException(oe);
+ }
}
/**
@@ -156,6 +160,9 @@ public class DeploymentServlet extends H
m_log.log(LogService.LOG_WARNING, e.getMessage(), e);
e.handleAsHttpError(response);
}
+ catch (OverloadedException oe) {
+ throw new ServletException(oe);
+ }
}
/**
@@ -211,7 +218,7 @@ public class DeploymentServlet extends H
* @param response
* response object.
*/
- private void handleVersionsRequest(String targetID, HttpServletResponse response) throws AceRestException {
+ private void handleVersionsRequest(String targetID, HttpServletResponse response) throws OverloadedException, AceRestException {
ServletOutputStream output = null;
List<String> versions = getVersions(targetID);
@@ -232,7 +239,7 @@ public class DeploymentServlet extends H
}
}
- private void handlePackageDelivery(String targetID, String version, HttpServletRequest request, HttpServletResponse response) throws AceRestException {
+ private void handlePackageDelivery(String targetID, String version, HttpServletRequest request, HttpServletResponse response) throws OverloadedException, AceRestException {
ServletOutputStream output = null;
List<String> versions = getVersions(targetID);
@@ -284,7 +291,7 @@ public class DeploymentServlet extends H
}
}
- private List<String> getVersions(String targetID) throws AceRestException {
+ private List<String> getVersions(String targetID) throws OverloadedException, AceRestException {
try {
return m_provider.getVersions(targetID);
}
Added: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/OverloadedFilter.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/OverloadedFilter.java?rev=1534794&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/OverloadedFilter.java (added)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/OverloadedFilter.java Tue Oct 22 21:16:47 2013
@@ -0,0 +1,57 @@
+/*
+ * 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.ace.deployment.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ace.deployment.provider.OverloadedException;
+
+public class OverloadedFilter implements Filter {
+
+ private static final String HTTP_RETRY_AFTER = "Retry-After";
+
+ @Override
+ public void init(FilterConfig config) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ try {
+ filterChain.doFilter(request, response);
+ }
+ catch (OverloadedException oe) {
+ OverloadedException overloadedException = (OverloadedException) oe;
+ httpResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ httpResponse.setHeader(HTTP_RETRY_AFTER, "" + overloadedException.getBackoffTime());
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/StreamGenerator.java Tue Oct 22 21:16:47 2013
@@ -21,6 +21,8 @@ package org.apache.ace.deployment.stream
import java.io.IOException;
import java.io.InputStream;
+import org.apache.ace.deployment.provider.OverloadedException;
+
public interface StreamGenerator
{
@@ -31,8 +33,9 @@ public interface StreamGenerator
* @param version the version of the package
* @return an input stream
* @throws java.io.IOException when the stream could not be generated
+ * @throws OverloadedException if the streamgenerator is overloaded
*/
- public InputStream getDeploymentPackage(String id, String version) throws IOException;
+ public InputStream getDeploymentPackage(String id, String version) throws OverloadedException, IOException;
/**
* Returns an input stream with the requested deployment fix package.
@@ -42,6 +45,7 @@ public interface StreamGenerator
* @param toVersion the version the target should be in after applying the package.
* @return an input stream.
* @throws java.io.IOException when the stream could not be generated.
+ * @throws OverloadedException if the streamgenerator is overloaded
*/
- public InputStream getDeploymentPackage(String id, String fromVersion, String toVersion) throws IOException;
+ public InputStream getDeploymentPackage(String id, String fromVersion, String toVersion) throws OverloadedException, IOException;
}
\ No newline at end of file
Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/StreamGeneratorImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/StreamGeneratorImpl.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/StreamGeneratorImpl.java (original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/streamgenerator/impl/StreamGeneratorImpl.java Tue Oct 22 21:16:47 2013
@@ -33,6 +33,7 @@ import java.util.zip.ZipEntry;
import org.apache.ace.connectionfactory.ConnectionFactory;
import org.apache.ace.deployment.provider.ArtifactData;
import org.apache.ace.deployment.provider.DeploymentProvider;
+import org.apache.ace.deployment.provider.OverloadedException;
import org.apache.ace.deployment.streamgenerator.StreamGenerator;
/**
@@ -43,15 +44,8 @@ public class StreamGeneratorImpl impleme
private volatile DeploymentProvider m_provider;
private volatile ConnectionFactory m_connectionFactory;
- /**
- * Returns an input stream with the requested deployment package.
- *
- * @param id the ID of the package
- * @param version the version of the package
- * @return an input stream
- * @throws java.io.IOException when the stream could not be generated
- */
- public InputStream getDeploymentPackage(String id, String version) throws IOException {
+ @Override
+ public InputStream getDeploymentPackage(String id, String version) throws OverloadedException, IOException {
List<ArtifactData> data = m_provider.getBundleData(id, version);
Manifest manifest = new Manifest();
Attributes main = manifest.getMainAttributes();
@@ -70,16 +64,8 @@ public class StreamGeneratorImpl impleme
return DeploymentPackageStream.createStreamForThread(m_connectionFactory, manifest, data.iterator(), false);
}
- /**
- * Returns an input stream with the requested deployment fix package.
- *
- * @param id the ID of the package.
- * @param fromVersion the version of the target.
- * @param toVersion the version the target should be in after applying the package.
- * @return an input stream.
- * @throws java.io.IOException when the stream could not be generated.
- */
- public InputStream getDeploymentPackage(String id, String fromVersion, String toVersion) throws IOException {
+ @Override
+ public InputStream getDeploymentPackage(String id, String fromVersion, String toVersion) throws OverloadedException, IOException {
//return execute(new WorkerFixPackage(id, fromVersion, toVersion));
List<ArtifactData> data = m_provider.getBundleData(id, fromVersion, toVersion);
Manifest manifest = new Manifest();
Modified: ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/MockDeploymentRepository.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/MockDeploymentRepository.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/MockDeploymentRepository.java (original)
+++ ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/MockDeploymentRepository.java Tue Oct 22 21:16:47 2013
@@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.concurrent.Semaphore;
import java.util.zip.GZIPOutputStream;
import org.apache.ace.range.SortedRangeSet;
@@ -31,10 +32,12 @@ public class MockDeploymentRepository im
private String m_range;
private String m_xmlRepository;
+ private Semaphore m_semaphore;
- public MockDeploymentRepository(String range, String xmlRepository) {
+ public MockDeploymentRepository(String range, String xmlRepository, Semaphore semaphore) {
m_range = range;
m_xmlRepository = xmlRepository;
+ m_semaphore = semaphore;
}
/* (non-Javadoc)
@@ -42,6 +45,15 @@ public class MockDeploymentRepository im
* @see org.apache.ace.repository.Repository#checkout(long)
*/
public InputStream checkout(long version) throws IOException, IllegalArgumentException {
+ if (m_semaphore != null) {
+ m_semaphore.release();
+ try {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
if (version == 1) {
//throw an IOException!
throw new IOException("Checkout exception.");
@@ -57,11 +69,29 @@ public class MockDeploymentRepository im
}
public boolean commit(InputStream data, long fromVersion) throws IOException, IllegalArgumentException {
+ if (m_semaphore != null) {
+ m_semaphore.release();
+ try {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
// Not used in test
return false;
}
public SortedRangeSet getRange() throws IOException {
+ if (m_semaphore != null) {
+ m_semaphore.release();
+ try {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
return new SortedRangeSet(m_range);
}
}
Added: ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderConcurrencyTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderConcurrencyTest.java?rev=1534794&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderConcurrencyTest.java (added)
+++ ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderConcurrencyTest.java Tue Oct 22 21:16:47 2013
@@ -0,0 +1,118 @@
+/*
+ * 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.ace.deployment.provider.repositorybased;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.ace.deployment.provider.OverloadedException;
+import org.apache.ace.repository.Repository;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class RepositoryBasedProviderConcurrencyTest {
+
+ private final String TARGET = "target";
+
+ private RepositoryBasedProvider m_backend;
+ private Semaphore m_semaphore;
+ private Exception m_exception;
+
+ @BeforeMethod(alwaysRun = true)
+ protected void setUp() throws Exception {
+ // setup mock repository
+ m_semaphore = new Semaphore(0);
+ MockDeploymentRepository repository = new MockDeploymentRepository("", null, m_semaphore);
+ m_backend = new RepositoryBasedProvider();
+ TestUtils.configureObject(m_backend, Repository.class, repository);
+ TestUtils.configureObject(m_backend, LogService.class);
+ }
+
+ @Test(groups = { UNIT })
+ public void testNoConcurrentUsersAllowed() throws Exception {
+ // -1 number of users makes sure nobody can use the repository
+ setConfigurationForUsers(-1);
+ try {
+ m_backend.getVersions(TARGET);
+ assert false : "Expected an overloaded exception";
+ } catch (OverloadedException oe) {
+ assert true;
+ } catch (Throwable t) {
+ assert false : "Unknown exception";
+ }
+ }
+
+ @Test(groups = { UNIT })
+ public void testConcurrentUsersWithLimit() throws Exception {
+ setConfigurationForUsers(1);
+ new Thread() {
+ public void run() {
+ try {
+ m_backend.getVersions(TARGET);
+ } catch (Exception e) {
+ m_exception = e;
+ }
+ }
+ }.start();
+
+ try {
+ boolean acquire = m_semaphore.tryAcquire(1, 1, TimeUnit.SECONDS);
+ assert acquire : "Could not acquire semaphore, no concurrent threads ?";
+ m_backend.getVersions(TARGET);
+ assert false : "Expected an overloaded exception";
+ } catch (OverloadedException oe) {
+ assert true;
+ }
+
+ assert m_exception == null : "No Exception expected";
+ }
+
+ @Test(groups = { UNIT })
+ public void testConcurrentUsersWithoutLimit() throws Exception {
+ // Because it's hard to test for unlimited users we'll just try 2 concurrent threads.
+ setConfigurationForUsers(0);
+ new Thread() {
+ public void run() {
+ try {
+ m_backend.getVersions(TARGET);
+ } catch (Exception e) {
+ m_exception = e;
+ }
+ }
+ }.start();
+
+ m_semaphore.tryAcquire(1, 1, TimeUnit.SECONDS);
+ m_backend.getVersions(TARGET);
+ assert true;
+
+ assert m_exception == null : "No Exception expected";
+ }
+
+ private void setConfigurationForUsers(int numberOfConcurrentUsers) throws Exception {
+ // setting a new configuration on the repository also creates a cache repository etc. This way only the max users is changed.
+ Field field = m_backend.getClass().getDeclaredField("m_maximumNumberOfUsers");
+ field.setAccessible(true);
+ field.set(m_backend, new Integer(numberOfConcurrentUsers));
+ }
+}
Modified: ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java (original)
+++ ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java Tue Oct 22 21:16:47 2013
@@ -99,7 +99,7 @@ public class RepositoryBasedProviderPerf
public void setUp() throws Exception {
// setup mock repository
String range = "1-100000";
- Repository mock = new MockDeploymentRepository(range, generateHugeTestXml());
+ Repository mock = new MockDeploymentRepository(range, generateHugeTestXml(), null);
m_backend = new RepositoryBasedProvider();
TestUtils.configureObject(m_backend, Repository.class, mock);
TestUtils.configureObject(m_backend, LogService.class);
Modified: ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderTest.java?rev=1534794&r1=1534793&r2=1534794&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderTest.java (original)
+++ ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderTest.java Tue Oct 22 21:16:47 2013
@@ -21,7 +21,6 @@ package org.apache.ace.deployment.provid
import static org.apache.ace.test.utils.TestUtils.UNIT;
import java.io.File;
-import java.io.IOException;
import java.io.StringWriter;
import java.util.Collection;
import java.util.HashMap;
@@ -146,7 +145,7 @@ public class RepositoryBasedProviderTest
String range = "1,2,3";
// setup mock repository
- Repository mock = new MockDeploymentRepository(range, deploymentRepositoryXml);
+ Repository mock = new MockDeploymentRepository(range, deploymentRepositoryXml, null);
m_backend = new RepositoryBasedProvider();
TestUtils.configureObject(m_backend, Repository.class, mock);
TestUtils.configureObject(m_backend, LogService.class);
@@ -359,8 +358,8 @@ public class RepositoryBasedProviderTest
* @throws java.io.IOException
*/
@Test(groups = { UNIT })
- public void testEmptyRepository() throws IOException {
- Repository mock = new MockDeploymentRepository("", null);
+ public void testEmptyRepository() throws Exception {
+ Repository mock = new MockDeploymentRepository("", null, null);
TestUtils.configureObject(m_backend, Repository.class, mock);
List<String> versions = m_backend.getVersions(TARGET);
@@ -372,7 +371,7 @@ public class RepositoryBasedProviderTest
* See if the getVersions() methods normal output works
*/
@Test(groups = { UNIT })
- public void testGetVersion() throws IOException {
+ public void testGetVersion() throws Exception {
List<String> versions = m_backend.getVersions(TARGET);
assert versions.size() == 1 : "Expected one version to be found, but found " + versions.size();
assert versions.get(0).equals(VERSION1) : "Expected version " + VERSION1 + " but found " + versions.get(0);
@@ -382,7 +381,7 @@ public class RepositoryBasedProviderTest
* Test the getVersions method with an illegal version (not in org.osgi.framework.Version format)
*/
@Test(groups = { UNIT })
- public void testIllegalVersion() throws IOException {
+ public void testIllegalVersion() throws Exception {
// an illegal version should be silently ignored
List<String> versions = m_backend.getVersions(INVALIDVERSIONTARGET);
assert versions.isEmpty() : "Expected no versions to be found, but found " + versions.size();
@@ -392,7 +391,7 @@ public class RepositoryBasedProviderTest
* Test with multiple versions. It expects all versions in an ascending order.
*/
@Test(groups = { UNIT })
- public void testMultipleVersions() throws IOException {
+ public void testMultipleVersions() throws Exception {
List<String> versions = m_backend.getVersions(MULTIPLEVERSIONTARGET);
assert versions.size() == 4 : "Expected three version to be found, but found " + versions.size();
// all versions should be in ascending order
@@ -406,7 +405,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a single version, returning a single bundle
*/
@Test(groups = { UNIT })
- public void testSingleBundleSingleVersionBundleData() throws IOException {
+ public void testSingleBundleSingleVersionBundleData() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(TARGET, VERSION1);
assert bundleData.size() == 1 : "Expected one bundle to be found, but found " + bundleData.size();
assert bundleData.contains(BUNDLE1) : "Expected to find bundle " + BUNDLE1.getSymbolicName();
@@ -416,7 +415,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a single version, returning a multiple bundles
*/
@Test(groups = { UNIT })
- public void testMultipleBundleSingleVersionBundleData() throws IOException {
+ public void testMultipleBundleSingleVersionBundleData() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(MULTIPLEVERSIONTARGET, VERSION1);
assert bundleData.size() == 2 : "Expected two bundle to be found, but found " + bundleData.size();
assert bundleData.contains(BUNDLE3) : "Expected to find bundle " + BUNDLE3.getSymbolicName();
@@ -427,7 +426,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData with an illegal version (i.e. a version that doesn't exist)
*/
@Test(groups = { UNIT })
- public void testInvalidVersionBundleData() throws IOException {
+ public void testInvalidVersionBundleData() throws Exception {
try {
m_backend.getBundleData(TARGET, INVALIDVERSION);
assert false : "Expected an error because version " + INVALIDVERSION + " doesn't exist for target: "
@@ -442,7 +441,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData with an illegal target (i.e. a target that doesn't exist)
*/
@Test(groups = { UNIT })
- public void testInvalidTargetBundleData() throws IOException {
+ public void testInvalidTargetBundleData() throws Exception {
try {
m_backend.getBundleData(INVALIDVERSIONTARGET, VERSION1);
assert false : "Expected an error because version " + VERSION1 + " doesn't exist for target: "
@@ -457,7 +456,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a two versions, returning a single bundle that hasn't changed
*/
@Test(groups = { UNIT })
- public void testSingleUnchangedBundleMultipleVersions() throws IOException {
+ public void testSingleUnchangedBundleMultipleVersions() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(TARGET, VERSION1, VERSION1);
assert bundleData.size() == 1 : "Expect one bundle, got " + bundleData.size();
Iterator<ArtifactData> it = bundleData.iterator();
@@ -472,7 +471,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a two versions, returning multiple bundles that haven't changed
*/
@Test(groups = { UNIT })
- public void testMultipleBundlesMultipleVersions() throws IOException {
+ public void testMultipleBundlesMultipleVersions() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(MULTIPLEVERSIONTARGET, VERSION1, VERSION1);
assert bundleData.size() == 2 : "Expected two bundle to be found, but found " + bundleData.size();
Iterator<ArtifactData> it = bundleData.iterator();
@@ -486,7 +485,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a two versions, where in the second version a bundle is removed
*/
@Test(groups = { UNIT })
- public void testRemovedBundleMultipleVersions() throws IOException {
+ public void testRemovedBundleMultipleVersions() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(MULTIPLEVERSIONTARGET, VERSION1, VERSION3);
assert bundleData.size() == 1 : "Expected one bundle to be found, but found " + bundleData.size();
}
@@ -495,7 +494,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a two versions, where in the second version a bundle is added
*/
@Test(groups = { UNIT })
- public void testAddedBundleMultipleVersions() throws IOException {
+ public void testAddedBundleMultipleVersions() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(MULTIPLEVERSIONTARGET, VERSION3, VERSION1);
assert bundleData.size() == 2 : "Expected two bundle to be found, but found " + bundleData.size();
Iterator<ArtifactData> it = bundleData.iterator();
@@ -514,7 +513,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a two versions, where in the second version one bundle has changed and another hasn't
*/
@Test(groups = { UNIT })
- public void testSingleChangedBundleMultipleVersions() throws IOException {
+ public void testSingleChangedBundleMultipleVersions() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(MULTIPLEVERSIONTARGET, VERSION1, VERSION4);
assert bundleData.size() == 2 : "Expected two bundles to be found, but found " + bundleData.size();
Iterator<ArtifactData> it = bundleData.iterator();
@@ -536,7 +535,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for a two versions, where two bundles have changed
*/
@Test(groups = { UNIT })
- public void testMultipleChangedBundlesMultipleVersions() throws IOException {
+ public void testMultipleChangedBundlesMultipleVersions() throws Exception {
Collection<ArtifactData> bundleData = m_backend.getBundleData(MULTIPLEVERSIONTARGET, VERSION1, VERSION2);
assert bundleData.size() == 2 : "Expected two bundles to be found, but found " + bundleData.size();
Iterator<ArtifactData> it = bundleData.iterator();
@@ -558,7 +557,7 @@ public class RepositoryBasedProviderTest
* See if the getVersions() methods normal output works with literals ' and "
*/
@Test(groups = { UNIT })
- public void testGetLiteralTargetVersion() throws IOException {
+ public void testGetLiteralTargetVersion() throws Exception {
List<String> versions = m_backend.getVersions("'");
assert versions.size() == 1 : "Expected one version to be found, but found " + versions.size();
assert versions.get(0).equals(VERSION1) : "Expected version " + VERSION1 + " but found " + versions.get(0);
@@ -580,7 +579,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData for an empty version (no bundle URLS are included)
*/
@Test(groups = { UNIT })
- public void testEmptyDeploymentVersion() throws IOException {
+ public void testEmptyDeploymentVersion() throws Exception {
// get the version number
List<String> versions = m_backend.getVersions(EMPTYVERSIONTARGET);
assert versions.size() == 2 : "Expected two version to be found, but found " + versions.size();
@@ -602,7 +601,7 @@ public class RepositoryBasedProviderTest
* See if a version with a literal is parsed correct and ignored.
*/
@Test(groups = { UNIT })
- public void testGetLiteralTargetIllegalVersion() throws IOException {
+ public void testGetLiteralTargetIllegalVersion() throws Exception {
List<String> versions = m_backend.getVersions("myTarget");
assert versions.size() == 0 : "Expected no versions to be found, but found " + versions.size();
}
@@ -611,7 +610,7 @@ public class RepositoryBasedProviderTest
* Test the getBundleData with some resources.
*/
@Test(groups = { UNIT })
- public void testBundleDataWithResources() throws IOException {
+ public void testBundleDataWithResources() throws Exception {
List<String> versions = m_backend.getVersions(RESOURCETARGET);
assert versions.size() == 1 : "Expected two version to be found, but found " + versions.size();