You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by br...@apache.org on 2013/04/16 13:06:21 UTC
svn commit: r1468366 - in /ace/trunk:
org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/
org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/
org.apache.ace.client.repository/src/org/apache/ace/c...
Author: bramk
Date: Tue Apr 16 11:06:20 2013
New Revision: 1468366
URL: http://svn.apache.org/r1468366
Log:
ACE-316 BundleFileStore now uses hierarchical layout based on BSN parts (splitted by dot)
ACE-317 Rest API POST now returns "201 - Created" with the actual location the resource
Modified:
ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/TemplateProcessorTest.java
ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java
ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java
ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java
ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/servlet/BundleServlet.java
ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/BundleStore.java
ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/file/BundleFileStore.java
ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java
ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java
ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java
Modified: ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/TemplateProcessorTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/TemplateProcessorTest.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/TemplateProcessorTest.java (original)
+++ ace/trunk/org.apache.ace.client.repository.itest/src/org/apache/ace/it/repositoryadmin/TemplateProcessorTest.java Tue Apr 16 11:06:20 2013
@@ -233,7 +233,7 @@ public class TemplateProcessorTest exten
String simpleTemplate = "<Attribute content=\"http://$context.name\"/>";
String simpleTemplateProcessed = "<Attribute content=\"http://mydistribution\"/>";
- File simpleTemplateFile = createFileWithContents("template", "xml", xmlHeader + simpleTemplate + xmlFooter);
+ File simpleTemplateFile = createFileWithContents("template", ".xml", xmlHeader + simpleTemplate + xmlFooter);
// create some tree from artifacts to a target
FeatureObject go = runAndWaitForEvent(new Callable<FeatureObject>() {
Modified: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java (original)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/ArtifactPreprocessorBase.java Tue Apr 16 11:06:20 2013
@@ -19,20 +19,13 @@
package org.apache.ace.client.repository.helper.base;
import java.io.Closeable;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
-import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
import org.apache.ace.client.repository.helper.ArtifactPreprocessor;
import org.apache.ace.connectionfactory.ConnectionFactory;
@@ -47,7 +40,6 @@ public abstract class ArtifactPreprocess
protected static final int BUFFER_SIZE = 64 * 1024;
protected final ConnectionFactory m_connectionFactory;
- private final ExecutorService m_executor;
/**
* Creates a new {@link ArtifactPreprocessorBase} instance.
@@ -57,7 +49,6 @@ public abstract class ArtifactPreprocess
*/
protected ArtifactPreprocessorBase(ConnectionFactory connectionFactory) {
m_connectionFactory = connectionFactory;
- m_executor = Executors.newCachedThreadPool();
}
/**
@@ -93,42 +84,6 @@ public abstract class ArtifactPreprocess
}
/**
- * Gets a stream to write an artifact to, which will be uploaded asynchronously to the OBR.
- *
- * @param name
- * The name of the artifact.
- * @param obrBase
- * The base URL of the obr to which this artifact should be written.
- * @param inputStream
- * the input stream with data to upload.
- */
- protected final Future<URL> uploadAsynchronously(final String name, final URL obrBase, final InputStream inputStream) {
- return m_executor.submit(new Callable<URL>() {
- public URL call() throws IOException {
- return upload(inputStream, name, obrBase);
- }
- });
- }
-
- /**
- * Converts a given URL to a {@link File} object.
- *
- * @param url
- * the URL to convert, cannot be <code>null</code>.
- * @return a {@link File} object, never <code>null</code>.
- */
- protected final File urlToFile(URL url) {
- File file;
- try {
- file = new File(url.toURI());
- }
- catch (URISyntaxException e) {
- file = new File(url.getPath());
- }
- return file;
- }
-
- /**
* Uploads an artifact synchronously to an OBR.
*
* @param input
@@ -142,7 +97,7 @@ public abstract class ArtifactPreprocess
* If there was an error reading from <code>input</code>, or if there was a problem communicating with
* the OBR.
*/
- private URL upload(InputStream input, String name, URL obrBase) throws IOException {
+ String upload(InputStream input, String name, String mimeType, URL obrBase) throws IOException {
if (obrBase == null) {
throw new IOException("There is no storage available for this artifact.");
}
@@ -150,79 +105,23 @@ public abstract class ArtifactPreprocess
throw new IllegalArgumentException("None of the parameters can be null.");
}
- URL url = null;
- try {
- url = determineNewUrl(name, obrBase);
-
- if (!urlPointsToExistingFile(url)) {
- if ("file".equals(url.getProtocol())) {
- uploadToFile(input, url);
- }
- else {
- uploadToRemote(input, url);
- }
- }
- }
- catch (IOException ioe) {
- throw new IOException("Error uploading " + name + ": " + ioe.getMessage());
- }
- finally {
- silentlyClose(input);
- }
-
- return url;
- }
-
- /**
- * Uploads an artifact to a local file location.
- *
- * @param input
- * the input stream of the (local) artifact to upload.
- * @param url
- * the URL of the (file) artifact to upload to.
- * @throws IOException
- * in case of I/O problems.
- */
- private void uploadToFile(InputStream input, URL url) throws IOException {
- File file = urlToFile(url);
-
OutputStream output = null;
-
+ String location = null;
try {
- output = new FileOutputStream(file);
-
- byte[] buffer = new byte[BUFFER_SIZE];
- for (int count = input.read(buffer); count != -1; count = input.read(buffer)) {
- output.write(buffer, 0, count);
- }
- }
- finally {
- silentlyClose(output);
- }
- }
- /**
- * Uploads an artifact to a remote location.
- *
- * @param input
- * the input stream of the (local) artifact to upload.
- * @param url
- * the URL of the (remote) artifact to upload to.
- * @throws IOException
- * in case of I/O problems, or when the upload was refused by the remote.
- */
- private void uploadToRemote(InputStream input, URL url) throws IOException {
- OutputStream output = null;
-
- try {
+ URL url = new URL(obrBase, "?filename=" + name);
URLConnection connection = m_connectionFactory.createConnection(url);
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+
+ connection.setRequestProperty("Content-Type", mimeType);
if (connection instanceof HttpURLConnection) {
// ACE-294: enable streaming mode causing only small amounts of memory to be
// used for this commit. Otherwise, the entire input stream is cached into
// memory prior to sending it to the server...
((HttpURLConnection) connection).setChunkedStreamingMode(8192);
}
- connection.setDoOutput(true);
output = connection.getOutputStream();
@@ -235,7 +134,8 @@ public abstract class ArtifactPreprocess
if (connection instanceof HttpURLConnection) {
int responseCode = ((HttpURLConnection) connection).getResponseCode();
switch (responseCode) {
- case HttpURLConnection.HTTP_OK:
+ case HttpURLConnection.HTTP_CREATED:
+ location = connection.getHeaderField("Location");
break;
case HttpURLConnection.HTTP_CONFLICT:
throw new IOException("Artifact already exists in storage.");
@@ -250,55 +150,6 @@ public abstract class ArtifactPreprocess
finally {
silentlyClose(output);
}
- }
-
- /**
- * Determines whether the given URL points to an existing file.
- *
- * @param url
- * the URL to test, cannot be <code>null</code>.
- * @return <code>true</code> if the given URL points to an existing file, <code>false</code> otherwise.
- */
- private boolean urlPointsToExistingFile(URL url) {
- boolean result = false;
-
- if ("file".equals(url.getProtocol())) {
- result = urlToFile(url).exists();
- }
- else {
- try {
- URLConnection connection = m_connectionFactory.createConnection(url);
-
- if (connection instanceof HttpURLConnection) {
- HttpURLConnection hc = (HttpURLConnection) connection;
-
- // Perform a HEAD on the file, to see whether it exists...
- hc.setRequestMethod("HEAD");
- try {
- int responseCode = hc.getResponseCode();
- result = (responseCode == HttpURLConnection.HTTP_OK);
- }
- finally {
- hc.disconnect();
- }
- }
- else {
- // In all other scenario's: try to read a single byte from the input
- // stream, if this succeeds, we can assume the file exists...
- InputStream is = connection.getInputStream();
- try {
- is.read();
- }
- finally {
- silentlyClose(is);
- }
- }
- }
- catch (IOException e) {
- // Ignore; assume file does not exist...
- }
- }
-
- return result;
+ return location;
}
}
Modified: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java (original)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/helper/base/VelocityArtifactPreprocessor.java Tue Apr 16 11:06:20 2013
@@ -33,8 +33,11 @@ import java.security.NoSuchAlgorithmExce
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.ace.client.repository.helper.PropertyResolver;
+import org.apache.ace.client.repository.helper.configuration.ConfigurationHelper;
import org.apache.ace.connectionfactory.ConnectionFactory;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
@@ -45,6 +48,9 @@ import org.apache.velocity.app.Velocity;
*/
public class VelocityArtifactPreprocessor extends ArtifactPreprocessorBase {
+ // matches a valid OSGi version
+ private final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)(\\.(\\d+)(\\.(\\d+)([\\.-]([\\w-]+))?)?)?");
+
private static Object m_initLock = new Object();
private static boolean m_velocityInitialized = false;
@@ -58,7 +64,6 @@ public class VelocityArtifactPreprocesso
*/
public VelocityArtifactPreprocessor(ConnectionFactory connectionFactory) {
super(connectionFactory);
-
try {
m_md5 = MessageDigest.getInstance("MD5");
}
@@ -72,13 +77,11 @@ public class VelocityArtifactPreprocesso
@Override
public boolean needsNewVersion(String url, PropertyResolver props, String targetID, String fromVersion) {
- // get the template
+
byte[] input = null;
byte[] result = null;
-
try {
init();
-
input = getArtifactAsBytes(url);
result = process(input, props);
}
@@ -88,7 +91,6 @@ public class VelocityArtifactPreprocesso
return true;
}
- // process the template
// first check: did we need any processing at all?
if (Arrays.equals(result, input)) {
return false;
@@ -102,7 +104,8 @@ public class VelocityArtifactPreprocesso
// Note: we do not cache any previously created processed templates, since the call that asks us to approve a new version
// may cross a pending needsNewVersion call.
- return !newHash.equals(oldHash);
+ boolean answer = !newHash.equals(oldHash);
+ return answer;
}
@Override
@@ -119,14 +122,18 @@ public class VelocityArtifactPreprocesso
// template isn't modified; use direct URL instead...
return url;
}
-
setHashForVersion(url, targetID, version, hash(result));
-
String name = getFilename(url, targetID, version);
-
- uploadAsynchronously(name, obrBase, new ByteArrayInputStream(result));
- return determineNewUrl(name, obrBase).toString();
+ String location = null;
+ if(obrBase.getProtocol().equals("http")){
+ // upload the new resource to the OBR
+ location = upload(new ByteArrayInputStream(result), name, ConfigurationHelper.MIMETYPE, obrBase);
+ } else {
+ // this is only to support the unit tests
+ location = obrBase + name;
+ }
+ return location;
}
/**
@@ -156,63 +163,70 @@ public class VelocityArtifactPreprocesso
}
/**
- * @param url
- * @param targetID
- * @param version
- * @return
- */
- private String getFilename(String url, String targetID, String version) {
+ * Creates a new filename for a processed template.
+ *
+ * @param url the original url
+ * @param targetID the targetID
+ * @param version the version
+ * @return a new filename
+ */
+ private String getFilename(String url, String targetID, String targetVersion) {
+
+ String fileName = "";
+ String fileExtension = "";
+ String fileVersion = "";
+
int indexOfLastSlash = url.lastIndexOf('/');
if (indexOfLastSlash != -1) {
- url = url.substring(indexOfLastSlash + 1);
+ fileName = url.substring(indexOfLastSlash + 1);
+ }
+ int indexOfLastDot = fileName.lastIndexOf('.');
+ if (indexOfLastDot != -1) {
+ fileExtension = fileName.substring(indexOfLastDot);
+ fileName = fileName.substring(0, indexOfLastDot);
+ }
+
+ int dashIndex = fileName.indexOf('-');
+ while (dashIndex != -1 && fileVersion.equals("")) {
+ String versionCandidate = fileName.substring(dashIndex + 1);
+ Matcher versionMatcher = VERSION_PATTERN.matcher(versionCandidate);
+ if(versionMatcher.matches()){
+ fileName = fileName.substring(0, dashIndex);
+ fileVersion = versionCandidate;
+ } else {
+ dashIndex = fileName.indexOf(fileName, dashIndex);
+ }
}
- return url + "-" + targetID + "-" + version;
- }
- /**
- * @param url
- * @param targetID
- * @param version
- * @return
- */
- private String getFullUrl(String url, String targetID, String version) {
- return url + "-" + targetID + "-" + version;
+ fileName = fileName + ".target-" + targetID + "-" + targetVersion + fileExtension;
+ return fileName;
}
/**
- * @param url
- * @param target
- * @param version
- * @return
+ * Creates a hash for caching.
+ *
+ * @param url the url
+ * @param target the target
+ * @param version the version
+ * @return a hash
*/
private String getHashForVersion(String url, String target, String version) {
String key = createHashKey(url, target, version);
-
Reference<String> ref = m_cachedHashes.get(key);
String hash = (ref != null) ? ref.get() : null;
- if (hash == null) {
- try {
- hash = hash(getBytesFromUrl(getFullUrl(url, target, version)));
-
- m_cachedHashes.put(key, new WeakReference<String>(hash));
- }
- catch (IOException e) {
- // we cannot retrieve the artifact, so we cannot say anything about it.
- }
- }
-
return hash;
}
/**
- * @param url
- * @param target
- * @param version
- * @param hash
+ * Adds a hash to the cache.
+ *
+ * @param url the url
+ * @param target the target
+ * @param version the version
+ * @param hash the hash
*/
private void setHashForVersion(String url, String target, String version, String hash) {
String key = createHashKey(url, target, version);
-
m_cachedHashes.put(key, new WeakReference<String>(hash));
}
@@ -227,7 +241,6 @@ public class VelocityArtifactPreprocesso
private byte[] process(byte[] input, PropertyResolver props) throws IOException {
VelocityContext context = new VelocityContext();
context.put("context", props);
-
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(baos);
@@ -249,7 +262,6 @@ public class VelocityArtifactPreprocesso
*/
private byte[] getArtifactAsBytes(String url) throws IOException {
byte[] result = null;
-
Reference<byte[]> ref = m_cachedArtifacts.get(url);
if (ref == null || ((result = ref.get()) == null)) {
result = getBytesFromUrl(url);
@@ -271,20 +283,16 @@ public class VelocityArtifactPreprocesso
InputStream in = m_connectionFactory.createConnection(new URL(url)).getInputStream();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
byte[] buf = new byte[BUFFER_SIZE];
for (int count = in.read(buf); count != -1; count = in.read(buf)) {
baos.write(buf, 0, count);
}
-
result = baos.toByteArray();
-
m_cachedArtifacts.put(url, new WeakReference<byte[]>(result));
}
finally {
silentlyClose(in);
}
-
return result;
}
Modified: ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java (original)
+++ ace/trunk/org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ArtifactRepositoryImpl.java Tue Apr 16 11:06:20 2013
@@ -121,14 +121,6 @@ public class ArtifactRepositoryImpl exte
ArtifactObjectImpl createNewInhabitant(Map<String, String> attributes, Map<String, String> tags) {
ArtifactHelper helper = getHelper(attributes.get(ArtifactObject.KEY_MIMETYPE));
ArtifactObjectImpl ao = new ArtifactObjectImpl(helper.checkAttributes(attributes), helper.getMandatoryAttributes(), tags, this, this);
- if ((ao.getAttribute("upload") != null) && (m_obrBase != null)) {
- try {
- ao.addAttribute(ArtifactObject.KEY_URL, new URL(m_obrBase, ao.getDefinition() + ao.getAttribute("upload")).toString());
- }
- catch (MalformedURLException e) {
- throw new IllegalStateException(e);
- }
- }
return ao;
}
@@ -353,34 +345,19 @@ public class ArtifactRepositoryImpl exte
}
String artifactURL = artifact.toString();
-
attributes.put(ArtifactObject.KEY_URL, artifactURL);
if (upload) {
- attributes.put("upload", recognizer.getExtension(resource));
- }
-
- ArtifactObject result = create(attributes, tags);
-
- if (upload) {
try {
- upload(artifact, result.getDefinition() + attributes.get("upload"), mimetype);
+ String location = upload(artifact, attributes.get("filename"), mimetype);
+ attributes.put(ArtifactObject.KEY_URL, location);
}
catch (IOException ex) {
- remove(result);
throw ex;
}
- finally {
- try {
- attributes.remove("upload");
- }
- catch (Exception ex) {
- // Not much we can do
- }
- }
}
+ ArtifactObject result = create(attributes, tags);
return result;
-
}
/**
@@ -427,25 +404,29 @@ public class ArtifactRepositoryImpl exte
*
* @param artifact
* URL pointing to the local artifact.
+ * @param filename
+ * The filenmame parameter, may be <code>null</code>.
* @param mimetype
* The mimetype of this artifact.
- * @return The persistent URL of this artifact.
+ * @return The persistent location of this artifact.
* @throws IOException
* for any problem uploading the artifact.
*/
- private URL upload(URL artifact, String definition, String mimetype) throws IOException {
+ private String upload(URL artifact, String filename, String mimetype) throws IOException {
if (m_obrBase == null) {
throw new IOException("There is no storage available for this artifact.");
}
InputStream input = null;
OutputStream output = null;
- URL url = null;
+ URL url = m_obrBase;
+ String location = null;
try {
input = openInputStream(artifact);
- url = new URL(m_obrBase, definition);
-
+ if(filename != null){
+ url = new URL(m_obrBase,"?filename=" + filename);
+ }
URLConnection connection = m_connectionFactory.createConnection(url);
connection.setDoOutput(true);
@@ -472,7 +453,8 @@ public class ArtifactRepositoryImpl exte
if (connection instanceof HttpURLConnection) {
int responseCode = ((HttpURLConnection) connection).getResponseCode();
switch (responseCode) {
- case HttpURLConnection.HTTP_OK:
+ case HttpURLConnection.HTTP_CREATED:
+ location = connection.getHeaderField("Location");
break;
case HttpURLConnection.HTTP_CONFLICT:
throw new IOException("Artifact already exists in storage.");
@@ -505,7 +487,7 @@ public class ArtifactRepositoryImpl exte
}
}
- return url;
+ return location;
}
public void setObrBase(URL obrBase) {
Modified: ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/servlet/BundleServlet.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/servlet/BundleServlet.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/servlet/BundleServlet.java (original)
+++ ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/servlet/BundleServlet.java Tue Apr 16 11:06:20 2013
@@ -18,6 +18,7 @@
*/
package org.apache.ace.obr.servlet;
+import static javax.servlet.http.HttpServletResponse.SC_CREATED;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
@@ -64,6 +65,7 @@ public class BundleServlet extends HttpS
private volatile BundleStore m_store; /* will be injected by dependencymanager */
private volatile AuthenticationService m_authService;
+ private volatile String m_servletEndpoint = "/";
private volatile boolean m_useAuth = false;
@Override
@@ -79,8 +81,18 @@ public class BundleServlet extends HttpS
throw new ConfigurationException(KEY_USE_AUTHENTICATION, "Missing or invalid value!");
}
boolean useAuth = Boolean.parseBoolean(useAuthString);
-
m_useAuth = useAuth;
+
+ m_servletEndpoint = (String) settings.get("org.apache.ace.server.servlet.endpoint");
+ if(m_servletEndpoint == null){
+ m_servletEndpoint = "/";
+ }
+ if(!m_servletEndpoint.startsWith("/")){
+ m_servletEndpoint = "/" + m_servletEndpoint;
+ }
+ if(!m_servletEndpoint.endsWith("/")){
+ m_servletEndpoint = m_servletEndpoint + "/";
+ }
}
else {
m_useAuth = false;
@@ -101,36 +113,32 @@ public class BundleServlet extends HttpS
}
/**
- * Responds to POST requests sent to http://host:port/obr/resource by writing the received data to the bundle store.
- * Will send out a response that contains one of the following status codes:
+ * Responds to POST requests sent to http://host:port/obr by writing the received data to the bundle store and
+ * returning the persistent location. Will send out a response that contains one of the following status codes:
* <ul>
* <li><code>HttpServletResponse.SC_BAD_REQUEST</code> - if no resource was specified</li>
* <li><code>HttpServletResponse.SC_CONFLICT</code> - if the resource already exists</li>
* <li><code>HttpServletResponse.SC_INTERNAL_SERVER_ERROR</code> - if there was a problem storing the resource</li>
- * <li><code>HttpServletResponse.SC_OK</code> - if all went fine</li>
+ * <li><code>HttpServletResponse.SC_CREATED</code> - if all went fine</li>
* </ul>
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
- String path = request.getPathInfo();
- if ((path == null) || (path.length() <= 1)) {
- sendResponse(response, SC_BAD_REQUEST);
- }
- else {
- String id = path.substring(1);
- try {
- if (m_store.put(id, request.getInputStream())) {
- sendResponse(response, SC_OK);
- }
- else {
- sendResponse(response, SC_CONFLICT);
- }
+
+ String fileName = request.getParameter("filename");
+ try {
+ String storePath = m_store.put(request.getInputStream(), fileName);
+ if (storePath != null) {
+ sendCreated(request, response, storePath);
}
- catch (IOException e) {
- m_log.log(LogService.LOG_WARNING, "Exception handling request: " + request.getRequestURL(), e);
- sendResponse(response, SC_INTERNAL_SERVER_ERROR);
+ else {
+ sendResponse(response, SC_CONFLICT);
}
}
+ catch (IOException e) {
+ m_log.log(LogService.LOG_WARNING, "Exception handling request: " + request.getRequestURL(), e);
+ sendResponse(response, SC_INTERNAL_SERVER_ERROR);
+ }
}
/**
@@ -315,6 +323,18 @@ public class BundleServlet extends HttpS
}
}
+ // send a created response with location header
+ private void sendCreated(HttpServletRequest request, HttpServletResponse response, String relativePath) {
+ StringBuilder locationBuiler = new StringBuilder(request.getScheme()).append("://").append(request.getServerName());
+ boolean ignorePort = (request.getScheme().equals("http") && request.getServerPort() == 80) | (request.getScheme().equals("https") && request.getServerPort() == 443);
+ if(!ignorePort){
+ locationBuiler.append(":" + request.getServerPort());
+ }
+ locationBuiler.append(m_servletEndpoint).append(relativePath);
+ response.setHeader("Location", locationBuiler.toString());
+ response.setStatus(SC_CREATED);
+ }
+
// send a response with the specified status code
private void sendResponse(HttpServletResponse response, int statusCode) {
sendResponse(response, statusCode, "");
Modified: ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/BundleStore.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/BundleStore.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/BundleStore.java (original)
+++ ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/BundleStore.java Tue Apr 16 11:06:20 2013
@@ -29,28 +29,31 @@ public interface BundleStore extends Man
/**
* Returns an <code>InputStream</code> to the data of the specified resource.
*
- * @param fileName Identifier of the requested resource.
+ * @param filePath Relative path of the the resource.
* @return <code>InputStream</code> to the requested resource or <code>null</code> if no such resource is available.
* @throws java.io.IOException If there was a problem returning the requested resource.
*/
- public InputStream get(String fileName) throws IOException;
+ public InputStream get(String filePath) throws IOException;
/**
- * Stores the specified resource in the store.
+ * Stores the specified resource in the store. For non OSGi bundles a valid filename must be specified that may
+ * contain a valid OSGi version.
+ * <br/><br/>
+ * Filename pattern: <code><filename>[-<version>].<extension><code>
*
- * @param fileName Identifier of the resource.
+ * @param fileName name of the resource, ignored if the resource is an OSGi bundle
* @param data The actual data of the resource.
- * @return <code>true</code> if the resource was successfully stored, <code>false</code> if the resource already existed
+ * @return the filePath if the resource was successfully stored, <code>null</code> if the resource already existed
* @throws java.io.IOException If there was a problem reading or writing the data of the resource.
*/
- public boolean put(String fileName, InputStream data) throws IOException;
-
+ public String put(InputStream data, String fileName) throws IOException;
+
/**
* Removes the specified resource from the store.
*
- * @param filename Identifier of the resource.
+ * @param filePath Relative path of the the resource.
* @return <code>true</code> if the resource was successfully removed, <code>false</code> if the resource was not present to begin with
* @throws java.io.IOException If there was a problem removing the data of the resource from the store.
*/
- public boolean remove(String filename) throws IOException;
+ public boolean remove(String filePath) throws IOException;
}
\ No newline at end of file
Modified: ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/file/BundleFileStore.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/file/BundleFileStore.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/file/BundleFileStore.java (original)
+++ ace/trunk/org.apache.ace.obr/src/org/apache/ace/obr/storage/file/BundleFileStore.java Tue Apr 16 11:06:20 2013
@@ -29,10 +29,16 @@ import java.nio.channels.FileChannel;
import java.util.Dictionary;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.ace.obr.metadata.MetadataGenerator;
import org.apache.ace.obr.storage.BundleStore;
import org.apache.ace.obr.storage.file.constants.OBRFileStoreConstants;
+import org.osgi.framework.Constants;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
@@ -43,6 +49,9 @@ import org.osgi.service.log.LogService;
*/
public class BundleFileStore implements BundleStore, ManagedService {
+ // matches a valid OSGi version
+ private final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)(\\.(\\d+)(\\.(\\d+)([\\.-]([\\w-]+))?)?)?");
+
private static int BUFFER_SIZE = 8 * 1024;
private static final String REPOSITORY_XML = "repository.xml";
@@ -79,28 +88,32 @@ public class BundleFileStore implements
return result;
}
- public boolean put(String fileName, InputStream data) throws IOException {
- final File file = createFile(fileName);
+ public String put(InputStream data, String fileName) throws IOException {
- boolean success = false;
- if (!file.exists()) {
- File folder = file.getAbsoluteFile().getParentFile();
- if (!folder.isDirectory() && !folder.mkdirs()) {
- throw new IOException("Could not create folder " + folder);
- }
- try {
- // the reason for first writing to a temporary file is that we want to minimize
- // the window where someone could be looking at a "partial" file that is still being
- // uploaded
- downloadToFile(data, file);
- success = true;
- }
- catch (IOException e) {
- // if anything goes wrong while reading from the input stream or
- // moving the file, delete the temporary file
- }
+ File tempFile = downloadToTempFile(data);
+
+ ResourceMetaData metaData = getBundleMetaData(tempFile);
+ if (metaData == null) {
+ metaData = getArtifactMetaData(fileName);
+ }
+ if (metaData == null) {
+ throw new IOException("Not a valid bundle and no filename found");
+ }
+
+ File storeLocation = getResourceFile(metaData);
+ if (storeLocation == null) {
+ throw new IOException("Failed to store resource");
+ }
+ if (storeLocation.exists()) {
+ return null;
}
- return success;
+
+ moveFile(tempFile, storeLocation);
+ String filePath = storeLocation.getAbsolutePath().substring(getWorkingDir().getAbsolutePath().length());
+ if(filePath.startsWith(File.separator)){
+ filePath = filePath.substring(1);
+ }
+ return filePath;
}
public boolean remove(String fileName) throws IOException {
@@ -188,20 +201,16 @@ public class BundleFileStore implements
}
/**
- * Downloads a given input stream to a temporary file and if done, moves it to its final location.
+ * Downloads a given input stream to a temporary file.
*
* @param source the input stream to download;
- * @param dest the destination to write the downloaded file to.
* @throws IOException in case of I/O problems.
*/
- private void downloadToFile(InputStream source, File dest) throws IOException {
+ private File downloadToTempFile(InputStream source) throws IOException {
File tempFile = File.createTempFile("obr", ".tmp");
-
FileOutputStream fos = null;
-
try {
fos = new FileOutputStream(tempFile);
-
int read;
byte[] buffer = new byte[BUFFER_SIZE];
while ((read = source.read(buffer)) >= 0) {
@@ -209,18 +218,125 @@ public class BundleFileStore implements
}
fos.flush();
fos.close();
-
- if (!tempFile.renameTo(dest)) {
- if (!moveFile(tempFile, dest)) {
- throw new IOException("Failed to move file store to its destination!");
+ return tempFile;
+ }
+ finally {
+ closeQuietly(fos);
+ }
+ }
+
+ /**
+ * Tries extract file metadata from a file assuming it is a valid OSGi bundle.
+ *
+ * @param file the file to analyze
+ * @return the metadata, or <code>null</code> if the file is not a valid bundle.
+ */
+ private ResourceMetaData getBundleMetaData(File file) {
+ JarInputStream jis = null;
+ try {
+ jis = new JarInputStream(new FileInputStream(file));
+ Manifest manifest = jis.getManifest();
+ if (manifest != null) {
+ Attributes attributes = manifest.getMainAttributes();
+ if (attributes != null) {
+ String bundleSymbolicName = attributes.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ String bundleVersion = attributes
+ .getValue(Constants.BUNDLE_VERSION);
+ if(bundleSymbolicName != null){
+ if(bundleVersion == null){
+ bundleVersion = "0.0.0";
+ }
+ return new ResourceMetaData(bundleSymbolicName, bundleVersion, "jar");
+ }
}
}
+ return null;
+ }
+ catch (Exception e) {
+ return null;
}
finally {
- closeQuietly(fos);
+ closeQuietly(jis);
+ }
+ }
+
+ /**
+ * Tries extract file metadata from a filename assuming a pattern. The version must be a valid OSGi version. If no
+ * version is found the default "0.0.0" is returned.
+ * <br/><br/>
+ * Filename pattern: <code><filename>[-<version>][.<extension>]<code>
+ *
+ * @param file the fileName to analyze
+ * @return the metadata, or <code>null</code> if the file is not a valid bundle.
+ */
+ private ResourceMetaData getArtifactMetaData(String fileName) {
+
+ if (fileName == null || fileName.equals("")) {
+ return null;
+ }
+
+ String symbolicName = null;
+ String version = null;
+ String extension = null;
+
+ // determine extension
+ String[] fileNameParts = fileName.split("\\.");
+ if (fileNameParts.length > 1) {
+ extension = fileNameParts[fileNameParts.length - 1];
+ symbolicName = fileName.substring(0, fileName.lastIndexOf('.'));
+ } else {
+ symbolicName = fileName;
+ }
+
+ // determine version
+ int dashIndex = symbolicName.indexOf('-');
+ while (dashIndex != -1 && version == null) {
+ String versionCandidate = symbolicName.substring(dashIndex + 1);
+ Matcher versionMatcher = VERSION_PATTERN.matcher(versionCandidate);
+ if(versionMatcher.matches()){
+ symbolicName = symbolicName.substring(0, dashIndex);
+ version = versionCandidate;
+ } else {
+ dashIndex = symbolicName.indexOf('-', dashIndex + 1);
+ }
+ }
+
+ if(version == null){
+ version = "0.0.0";
+ }
+ return new ResourceMetaData(symbolicName, version, extension);
+ }
+
+ /**
+ * Encapsulated the store layout strategy by creating the resource file based on the provided meta-data.
+ *
+ * @param metaData the meta-data for the resource
+ * @return the resource file
+ * @throws IOException in case of I/O problems.
+ */
+ private File getResourceFile(ResourceMetaData metaData) throws IOException {
- tempFile.delete();
+ File resourceFile = null;
+ String[] dirs = metaData.getSymmbolicName().split("\\.");
+ for (String subDir : dirs) {
+ if (resourceFile == null) {
+ resourceFile = new File(getWorkingDir(), subDir);
+ }
+ else {
+ resourceFile = new File(resourceFile, subDir);
+ }
}
+ if(!resourceFile.exists() && !resourceFile.mkdirs()){
+ throw new IOException("Failed to create store directory");
+ }
+
+ if (metaData.getExtension() != null && !metaData.getExtension().equals("")) {
+ resourceFile = new File(resourceFile, metaData.getSymmbolicName() + "-" + metaData.getVersion() + "." + metaData.getExtension());
+ }
+ else {
+ resourceFile = new File(resourceFile, metaData.getSymmbolicName() + "-" + metaData.getVersion());
+ }
+ return resourceFile;
}
/**
@@ -310,4 +426,32 @@ public class BundleFileStore implements
private File createFile(String fileName) {
return new File(getWorkingDir(), fileName);
}
+
+ /**
+ * Wrapper that holds resource meta-data relevant to the store layout.
+ *
+ */
+ static class ResourceMetaData {
+ private final String m_bundleSymbolicName;
+ private final String m_version;
+ private final String m_extension;
+
+ public ResourceMetaData(String bundleSymbolicName, String version, String extension){
+ m_bundleSymbolicName = bundleSymbolicName;
+ m_version = version;
+ m_extension = extension;
+ }
+
+ public String getSymmbolicName(){
+ return m_bundleSymbolicName;
+ }
+
+ public String getVersion(){
+ return m_version;
+ }
+
+ public String getExtension(){
+ return m_extension;
+ }
+ }
}
\ No newline at end of file
Modified: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java (original)
+++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java Tue Apr 16 11:06:20 2013
@@ -65,6 +65,22 @@ public class BundleServletTest {
TestUtils.configureObject(m_bundleServlet, BundleStore.class, m_store);
m_request = TestUtils.createMockObjectAdapter(HttpServletRequest.class, new Object() {
+
+ @SuppressWarnings("unused")
+ public String getScheme() {
+ return "http";
+ }
+
+ @SuppressWarnings("unused")
+ public String getServerName() {
+ return "localhost";
+ }
+
+ @SuppressWarnings("unused")
+ public int getServerPort() {
+ return 9999;
+ }
+
@SuppressWarnings("unused")
public String getParameter(String param) {
return m_requestFile;
@@ -119,6 +135,11 @@ public class BundleServletTest {
}
@SuppressWarnings("unused")
+ public void setStatus(int status) {
+ m_status = status;
+ }
+
+ @SuppressWarnings("unused")
public void sendError(int status) {
m_status = status;
}
@@ -179,20 +200,10 @@ public class BundleServletTest {
public void testPostResource() throws Exception {
m_requestFile = "NewFile";
m_bundleServlet.doPost(m_request, m_response);
- assert m_status == HttpServletResponse.SC_OK;
+ assert m_status == HttpServletResponse.SC_CREATED;
m_requestFile = "ExistingFile";
m_bundleServlet.doPost(m_request, m_response);
assert m_status == HttpServletResponse.SC_CONFLICT;
- m_requestFile = "";
- m_bundleServlet.doPost(m_request, m_response);
- assert m_status == HttpServletResponse.SC_BAD_REQUEST;
- }
-
- @Test(groups = { UNIT })
- public void testPostResourceInPath() throws Exception {
- m_requestFile = "path/to/file";
- m_bundleServlet.doPost(m_request, m_response);
- assert m_status == HttpServletResponse.SC_OK;
}
@Test(groups = { UNIT })
Modified: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java (original)
+++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java Tue Apr 16 11:06:20 2013
@@ -20,7 +20,6 @@ package org.apache.ace.obr.servlet;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.util.Dictionary;
import org.apache.ace.obr.storage.BundleStore;
@@ -41,18 +40,14 @@ public class MockBundleStore implements
return m_outFile;
}
- public void put(String fileName, OutputStream data) throws IOException {
- // TODO does nothing yet
- }
-
- public boolean put(String fileName, InputStream data) throws IOException {
+ public String put(InputStream data, String fileName) throws IOException {
if (fileName.equals("NewFile")) {
- return true;
+ return "NewFile";
}
if (fileName.equals("path/to/file")) {
- return true;
+ return "path/to/file";
}
- return false;
+ return null;
}
public boolean remove(String fileName) throws IOException {
Modified: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java?rev=1468366&r1=1468365&r2=1468366&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java (original)
+++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java Tue Apr 16 11:06:20 2013
@@ -20,7 +20,6 @@ package org.apache.ace.obr.storage.file;
import static org.apache.ace.test.utils.TestUtils.UNIT;
-import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -30,12 +29,15 @@ import java.io.OutputStream;
import java.util.Arrays;
import java.util.Properties;
import java.util.Random;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
import org.apache.ace.obr.metadata.MetadataGenerator;
-import org.apache.ace.obr.storage.BundleStore;
import org.apache.ace.obr.storage.file.constants.OBRFileStoreConstants;
import org.apache.ace.test.utils.FileUtils;
import org.apache.ace.test.utils.TestUtils;
+import org.osgi.framework.Constants;
import org.osgi.service.cm.ConfigurationException;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
@@ -43,7 +45,7 @@ import org.testng.annotations.Test;
public class BundleFileStoreTest {
- private BundleStore m_bundleStore;
+ private BundleFileStore m_bundleStore;
private MockMetadataGenerator m_metadata;
private File m_directory;
@@ -99,12 +101,12 @@ public class BundleFileStoreTest {
*/
@Test(groups = { UNIT })
public void getNonExistingBundle() throws Exception {
- assert m_bundleStore.get("blaat") == null : "Getting an non-existing file did not result in null?";
+ assert m_bundleStore.get("blaat") == null : "Getting an non-existing file did not result in null?";
}
/**
- * Test whether retrieving the repository.xml results in a call to the (mock) metadata generator,
- * and the original file should correspond with the retrieved file.
+ * Test whether retrieving the repository.xml results in a call to the (mock) metadata generator, and the original
+ * file should correspond with the retrieved file.
*/
@Test(groups = { UNIT })
public void getRepositoryFile() throws Exception {
@@ -122,8 +124,8 @@ public class BundleFileStoreTest {
}
/**
- * Test whether the BundleStore notices the set of bundles has changed (bundle updated),
- * and makes a call to the (mock) metadata generator.
+ * Test whether the BundleStore notices the set of bundles has changed (bundle updated), and makes a call to the
+ * (mock) metadata generator.
*/
@Test(groups = { UNIT })
public void updateBundle() throws Exception {
@@ -140,10 +142,9 @@ public class BundleFileStoreTest {
}
/**
- * Test whether the BundleStore notices the set of bundles has changed (bundle added),
- * and makes a call to the (mock) metadata generator. Also a call should be made when
- * a bundle is replaced by another one (number of bundles stay the same, but one bundle
- * is replaced by another).
+ * Test whether the BundleStore notices the set of bundles has changed (bundle added), and makes a call to the
+ * (mock) metadata generator. Also a call should be made when a bundle is replaced by another one (number of bundles
+ * stay the same, but one bundle is replaced by another).
*/
@Test(groups = { UNIT })
public void addBundle() throws Exception {
@@ -167,8 +168,8 @@ public class BundleFileStoreTest {
}
/**
- * Test whether the BundleStore notices the set of bundles has not changed, and thus
- * will not make a call to the (mock) metadata generator.
+ * Test whether the BundleStore notices the set of bundles has not changed, and thus will not make a call to the
+ * (mock) metadata generator.
*/
@Test(groups = { UNIT })
public void replaceWithSameBundle() throws Exception {
@@ -191,9 +192,8 @@ public class BundleFileStoreTest {
}
/**
- * Test whether changing the directory where the bundles are stored, does not result in a call
- * to the (mock) metadata generator, as the metadata will only be regenerated after getting
- * a file.
+ * Test whether changing the directory where the bundles are stored, does not result in a call to the (mock)
+ * metadata generator, as the metadata will only be regenerated after getting a file.
*/
@Test(groups = { UNIT })
public void updateConfigurationWithValidConfiguration() throws Exception {
@@ -216,8 +216,8 @@ public class BundleFileStoreTest {
}
/**
- * Test whether changing the directory where the bundles are stored to something that is not
- * a directory, this should fail.
+ * Test whether changing the directory where the bundles are stored to something that is not a directory, this
+ * should fail.
*/
@Test(groups = { UNIT })
public void updateConfigurationWithIsNotDirectory() throws Exception {
@@ -243,68 +243,100 @@ public class BundleFileStoreTest {
@Test(groups = { UNIT })
public void putBundle() throws Exception {
- String fileName = "filename";
- m_bundleStore.put(fileName, new ByteArrayInputStream("a".getBytes()));
- File file = new File(m_directory, fileName);
- FileInputStream input = new FileInputStream(file);
- assert input.read() == 'a';
- assert input.read() == -1;
- input.close();
+ File bundle = createTmpResource("foo.bar", "1.0.0");
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), null);
+ assert filePath.equals("foo/bar/foo.bar-1.0.0.jar");
+ File file = new File(m_directory, filePath);
+ assert file.exists();
}
@Test(groups = { UNIT })
- public void putBundleInPathAndRemoveItAgain() throws Exception {
- String fileName = "path/to/filename";
- m_bundleStore.put(fileName, new ByteArrayInputStream("a".getBytes()));
- File file = new File(m_directory, fileName);
- FileInputStream input = new FileInputStream(file);
- assert input.read() == 'a';
- assert input.read() == -1;
- input.close();
- assert m_bundleStore.remove(fileName);
+ public void putBundleDuplicate() throws Exception {
+ File bundle = createTmpResource("foo.bar", "1.0.0");
+ m_bundleStore.put(new FileInputStream(bundle), null);
+ String filePath2 = m_bundleStore.put(new FileInputStream(bundle), null);
+ assert filePath2 == null;
+ }
+
+ @Test(groups = { UNIT }, expectedExceptions = { IOException.class }, expectedExceptionsMessageRegExp = "Not a valid bundle and no filename found")
+ public void putBundleFail() throws Exception {
+ File bundle = createTmpResource(null, "1.0.0");
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), null);
+ assert filePath.equals("foo/bar/foo.bar-1.0.0.jar");
+ File file = new File(m_directory, filePath);
+ assert file.exists();
}
@Test(groups = { UNIT })
- public void putBundleInInvalidPathShouldFail() throws Exception {
- String fileName = "path/to/name";
- String fileName2 = "path/to/name/invalid";
- m_bundleStore.put(fileName, new ByteArrayInputStream("a".getBytes()));
- try {
- m_bundleStore.put(fileName2, new ByteArrayInputStream("a".getBytes()));
- assert false;
- }
- catch (IOException e) {
- // we expect this to happen
- }
+ public void putRemoveArtifact() throws Exception {
+ File bundle = createTmpResource(null, null);
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), "foo.bar-2.3.7.test1.xxx");
+ assert filePath.equals("foo/bar/foo.bar-2.3.7.test1.xxx");
+ File file = new File(m_directory, filePath);
+ assert file.exists();
}
-
@Test(groups = { UNIT })
- public void removeExistingBundle() throws Exception {
- m_bundleStore.put("filename", new InputStream() {
- private int i = 0;
+ public void putArtifactDefaultVersion() throws Exception {
+ File bundle = createTmpResource(null, null);
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), "foo.bar.xxx");
+ assert filePath.equals("foo/bar/foo.bar-0.0.0.xxx");
+ File file = new File(m_directory, filePath);
+ assert file.exists();
+ }
- @Override
- public int read() throws IOException {
- if (i < 1) {
- i++;
- return 'a';
- }
- else {
- return -1;
- }
- }
- });
- File file = new File(m_directory, "filename");
+ @Test(groups = { UNIT })
+ public void putArtifactMavenVersion() throws Exception {
+ File bundle = createTmpResource(null, null);
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), "foo.bar-2.3.7-test1.xxx");
+ assert filePath.equals("foo/bar/foo.bar-2.3.7-test1.xxx");
+ File file = new File(m_directory, filePath);
assert file.exists();
- m_bundleStore.remove("filename");
+ }
+
+ @Test(groups = { UNIT }, expectedExceptions = { IOException.class }, expectedExceptionsMessageRegExp = "Not a valid bundle and no filename found")
+ public void putArtifactFail1() throws Exception {
+ File bundle = createTmpResource(null, null);
+ m_bundleStore.put(new FileInputStream(bundle), null);
+ }
+
+ @Test(groups = { UNIT }, expectedExceptions = { IOException.class }, expectedExceptionsMessageRegExp = "Not a valid bundle and no filename found")
+ public void putArtifactFail2() throws Exception {
+ File bundle = createTmpResource(null, null);
+ m_bundleStore.put(new FileInputStream(bundle), "");
+ }
+
+ @Test(groups = { UNIT })
+ public void removeBundle() throws Exception {
+ File bundle = createTmpResource("foo.bar", "1.0.0");
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), null);
+ File file = new File(m_directory, filePath);
+ assert file.exists();
+ assert m_bundleStore.remove(filePath);
+ assert !file.exists();
+ }
+
+ @Test(groups = { UNIT })
+ public void removeBundleFaill() throws Exception {
+ File file = new File(m_directory, "no/such/file");
+ assert !file.exists();
+ assert !m_bundleStore.remove("no/such/file");
+ }
+
+ @Test(groups = { UNIT })
+ public void removeArtifact() throws Exception {
+ File bundle = createTmpResource(null, null);
+ String filePath = m_bundleStore.put(new FileInputStream(bundle), "foo.bar-2.3.7.test1.xxx");
+ assert filePath.equals("foo/bar/foo.bar-2.3.7.test1.xxx");
+ File file = new File(m_directory, filePath);
+ assert file.exists();
+ assert m_bundleStore.remove("foo/bar/foo.bar-2.3.7.test1.xxx");
assert !file.exists();
}
/**
- * Test whether not configuring the directory (so retrieving the directory returns null),
- * results in a ConfigurationException. Updating with null as dictionary should only clean up
- * things, and nothing else.
+ * Test whether not configuring the directory (so retrieving the directory returns null), results in a
+ * ConfigurationException. Updating with null as dictionary should only clean up things, and nothing else.
*/
@Test(groups = { UNIT })
public void updateConfigurationWithNull() throws Exception {
@@ -320,7 +352,6 @@ public class BundleFileStoreTest {
assert exceptionThrown : "Reconfiguring directory succeeded but should fail, as property is supposed to be missing";
assert !m_metadata.generated() : "After changing the directory, the metadata should not be regenerated.";
-
exceptionThrown = false;
try {
m_bundleStore.updated(null);
@@ -333,8 +364,8 @@ public class BundleFileStoreTest {
}
/**
- * Test whether not configuring the directory (so retrieving the directory returns null),
- * results in a ConfigurationException.
+ * Test whether not configuring the directory (so retrieving the directory returns null), results in a
+ * ConfigurationException.
*/
@Test(groups = { UNIT })
public void updateConfigurationWithSameDirectory() throws Exception {
@@ -350,6 +381,23 @@ public class BundleFileStoreTest {
assert !m_metadata.generated() : "After changing the directory, the metadata should not be regenerated.";
}
+ private File createTmpResource(String symbolicName, String version) throws IOException {
+ File tmpFile = File.createTempFile("tmpbundle-", "jar");
+ tmpFile.deleteOnExit();
+
+ Manifest manifest = new Manifest();
+ manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ if (symbolicName != null) {
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, symbolicName);
+ }
+ if (version != null) {
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_VERSION, version);
+ }
+ JarOutputStream target = new JarOutputStream(new FileOutputStream(tmpFile), manifest);
+ target.close();
+ return tmpFile;
+ }
+
private File createFileWithContent(File baseDir, String filename, int size) throws IOException {
OutputStream fileOut = null;
File file = new File(baseDir, filename);
@@ -359,7 +407,6 @@ public class BundleFileStoreTest {
Random randomContentCreator = new Random();
randomContentCreator.nextBytes(byteArray);
fileOut.write(byteArray);
-
return file;
}
finally {
@@ -373,6 +420,4 @@ public class BundleFileStoreTest {
}
}
}
-
-
}