users@jersey.java.net

Re: [Jersey] Hello World! and Welcome to jersey-multipart

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Tue, 04 Nov 2008 11:53:27 -0800

Paul Sandoz wrote:
>
>> Paul, the InjectableProvider stuff[1] in Jersey would support this,
>> right?
>
> Possibly... :-)
>
>
Until now I hadn't actually tried building my own injectable provider.
It turns out to be pretty straightforward, but with only one bit of
grief ... it doesn't work for me on the client side :-(. The complete
diff (from the current trunk) that I am playing with is attached, but
here's the highlights:

* A new JavaBean (MultiPartConfig) that represents the
  configuration data. Right now it's just a dummy with a
  hard coded value, but if this experiment works out we can
  easily make it look up the parameters in a properties file
  or something.

* A new provider annotation (MultiPartConfigParam) to
  declare the injectable type.

* A new provider (MultiPartConfigProvider) that serves as
  a factory for MultiPartConfig instances. I declared the
  scope to be singleton because there only needs to be
  one of these things around.

* Modifications to MultiPartReader to accept injection of the
  configuration parameter bean in the constructor:

    public MultiPartReader(@MultiPartConfigParam MultiPartConfig config) {
        this.config = config;
    }

  and modifications to call the getThresholdValue() method on
  the config bean when constructing a new BodyPartEntity
  (instead of the hard coded 4096 value).

* Modified unit test (MultiPartReaderWriterTest) to declare this
  additional provider in the configuration of the Jersey client.
  (Side question -- why do I have to configure these at all?
  I'm trying to use the package resources scanner.)

Things seem to work fine on the server side ... the new provider is
recognized, and a proper injection takes place. But on the client side,
it injects null (and therefore triggers NPEs in the tests that try to
parse a multipart response in the client).

Any ideas? Full diff is attached.

Craig

PS: Separately, an important implication of making this change is that
the jersey-multipart support would indeed by tied specifically to
Jersey, and not portable to other JAX-RS environments.

=============================================================================



Index: src/test/java/com/sun/jersey/impl/multipart/MultiPartReaderWriterTest.java
===================================================================
--- src/test/java/com/sun/jersey/impl/multipart/MultiPartReaderWriterTest.java (revision 1663)
+++ src/test/java/com/sun/jersey/impl/multipart/MultiPartReaderWriterTest.java (working copy)
@@ -88,6 +88,7 @@
         config.getClasses().add(MultiPartReader.class);
         config.getClasses().add(MultiPartWriter.class);
         config.getClasses().add(MultiPartBeanProvider.class);
+ config.getClasses().add(MultiPartConfigProvider.class);
         client = Client.create(config);
     }
 
Index: src/main/java/com/sun/jersey/impl/multipart/MultiPartConfigProvider.java
===================================================================
--- src/main/java/com/sun/jersey/impl/multipart/MultiPartConfigProvider.java (revision 0)
+++ src/main/java/com/sun/jersey/impl/multipart/MultiPartConfigProvider.java (revision 0)
@@ -0,0 +1,76 @@
+/*
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://jersey.dev.java.net/CDDL+GPL.html
+ * or jersey/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at jersey/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.jersey.impl.multipart;
+
+import com.sun.jersey.api.multipart.MultiPartConfigParam;
+import com.sun.jersey.api.multipart.MultiPartConfig;
+import com.sun.jersey.core.spi.component.ComponentContext;
+import com.sun.jersey.core.spi.component.ComponentScope;
+import com.sun.jersey.spi.inject.Injectable;
+import com.sun.jersey.spi.inject.InjectableProvider;
+import java.lang.reflect.Type;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * <p>Jersey-specific injectable provider that supplies a configured instance
+ * of {_at_link MultiPartConfig} for this application.</p>
+ */
+_at_Provider
+public class MultiPartConfigProvider implements InjectableProvider<MultiPartConfigParam, Type> {
+
+ public ComponentScope getScope() {
+ return ComponentScope.Singleton;
+ }
+
+ public Injectable getInjectable(ComponentContext ic, MultiPartConfigParam a, Type t) {
+ if (!(t instanceof Class)) {
+ System.out.println("Type " + t.toString() + " is not a Class"); // FIXME - remove debug statement
+ return null;
+ }
+ if (((Class) t).isPrimitive()) {
+ System.out.println("Type " + t.toString() + " is a primitive"); // FIXME - remove debug statement
+ return null;
+ }
+ return new Injectable<Object>() {
+ public Object getValue() {
+ return new MultiPartConfig();
+ }
+ };
+ }
+
+}

Property changes on: src/main/java/com/sun/jersey/impl/multipart/MultiPartConfigProvider.java
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Index: src/main/java/com/sun/jersey/impl/multipart/MultiPartReader.java
===================================================================
--- src/main/java/com/sun/jersey/impl/multipart/MultiPartReader.java (revision 1663)
+++ src/main/java/com/sun/jersey/impl/multipart/MultiPartReader.java (working copy)
@@ -40,6 +40,8 @@
 import com.sun.jersey.api.multipart.BodyPart;
 import com.sun.jersey.api.multipart.BodyPartEntity;
 import com.sun.jersey.api.multipart.MultiPart;
+import com.sun.jersey.api.multipart.MultiPartConfigParam;
+import com.sun.jersey.api.multipart.MultiPartConfig;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -69,6 +71,22 @@
 public class MultiPartReader implements MessageBodyReader<MultiPart> {
 
     /**
+ * <p>Accept constructor injection of the configuration parameters for this
+ * application.</p>
+ */
+ public MultiPartReader(@MultiPartConfigParam MultiPartConfig config) {
+ System.out.println("MultiPartConfigBean = " + config);
+ this.config = config;
+ }
+
+
+ /**
+ * <p>Injected configuration parameters for this application.</p>
+ */
+ private MultiPartConfig config = null;
+
+
+ /**
      * <P>Injectable helper to look up appropriate {_at_link Provider}s
      * for our body parts.</p>
      */
@@ -138,8 +156,7 @@
                 MediaType bpMediaType = MediaType.valueOf(bp.getContentType());
                 bodyPart.setMediaType(bpMediaType);
                 // Copy data into a BodyPartEntity structure
- // FIXME - how to make in-memory threshold value configurable
- bodyPart.setEntity(new BodyPartEntity(bp.getInputStream(), 4096));
+ bodyPart.setEntity(new BodyPartEntity(bp.getInputStream(), config.getBufferThreshold()));
                 // Add this BodyPart to our MultiPart
                 multiPart.getBodyParts().add(bodyPart);
             }
Index: src/main/java/com/sun/jersey/api/multipart/MultiPartConfig.java
===================================================================
--- src/main/java/com/sun/jersey/api/multipart/MultiPartConfig.java (revision 0)
+++ src/main/java/com/sun/jersey/api/multipart/MultiPartConfig.java (revision 0)
@@ -0,0 +1,56 @@
+/*
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://jersey.dev.java.net/CDDL+GPL.html
+ * or jersey/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at jersey/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.jersey.api.multipart;
+
+/**
+ * <p>Injectable JavaBean containing the configuration parameters for
+ * <code>jersey-multipart</code> as used in this particular application.</p>
+ */
+public class MultiPartConfig {
+
+
+ /**
+ * <p>Return the size (in bytes) of the entity of an incoming
+ * {_at_link BodyPart} before it will be buffered to disk.</p>
+ */
+ public int getBufferThreshold() {
+ return 4096; // FIXME - configure this from a properties file or something
+ }
+
+
+}

Property changes on: src/main/java/com/sun/jersey/api/multipart/MultiPartConfig.java
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Index: src/main/java/com/sun/jersey/api/multipart/MultiPartConfigParam.java
===================================================================
--- src/main/java/com/sun/jersey/api/multipart/MultiPartConfigParam.java (revision 0)
+++ src/main/java/com/sun/jersey/api/multipart/MultiPartConfigParam.java (revision 0)
@@ -0,0 +1,53 @@
+/*
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://jersey.dev.java.net/CDDL+GPL.html
+ * or jersey/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at jersey/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.jersey.api.multipart;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>Annotation describing an injectable {_at_link MultiPartConfigBean}.</p>
+ */
+_at_Target(value={ElementType.PARAMETER,ElementType.METHOD,ElementType.FIELD})
+_at_Retention(value=RetentionPolicy.RUNTIME)
+_at_Documented
+public @interface MultiPartConfigParam {
+}

Property changes on: src/main/java/com/sun/jersey/api/multipart/MultiPartConfigParam.java
___________________________________________________________________
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Index: pom.xml
===================================================================
--- pom.xml (revision 1663)
+++ pom.xml (working copy)
@@ -67,7 +67,7 @@
             <groupId>com.sun.jersey</groupId>
             <artifactId>jersey-core</artifactId>
             <version>${project.version}</version>
- <scope>test</scope>
+<!-- <scope>test</scope> -->
         </dependency>
         <dependency>
             <groupId>com.sun.jersey</groupId>