Is Representation in acceptRepresentation == Request.getEntity() ?
If I am implementing: public void acceptRepresentation( Representation rep ) { // ... } Is using that rep exactly the same as if I had instead done: Representation rep1 = getRequest().getEntity(); ? Is the rep being passed to acceptRepresentation() just a convenience? - Paul -- http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447dsMessageId=2380079
Form parsing doesn't work
I have a bit of code that processes a multipart/form-data form. I'm sending a test request using curl, e.g.: curl -v -F from=paul%40lucasmail.org http://localhost:8182/foo; I have code that parses the form that starts off with: final MediaType mediaType = request.getEntity().getMediaType(); final Form form = MediaType.APPLICATION_WWW_FORM.equals( mediaType, true ) || MediaType.MULTIPART_FORM_DATA.equals( mediaType, true ) ? request.getEntityAsForm() : request.getResourceRef().getQueryAsForm(); The form data isn't parsed correctly: the one and only name is the boundary string. The FormReader class doesn't seem to handle multipart/form-data. I'm using an older Restlet version (1.0.9), but I tried upgrading to 1.1.2 and it makes no difference. How to I parse multipart/form-data forms correctly? (Preferably using 1.0.9.) - Paul -- http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447dsMessageId=1188665
ERROR: 'Broken pipe'
I've been seeing a lot of: ERROR: 'Broken pipe' Exception intercepted @ HttpServerConverter.commit lately. What exactly does it mean? How can I print out the exception? And possible how to debug this? I'm using Restlet 1.0.9. - Paul
Re: Knowing if a client disconnected?
On Aug 13, 2008, at 9:53 AM, Jerome Louvel wrote: If the socket is broken or was closed by the client while the response is written, you won't be able to restore it. However, you can log the fact the you got this request from this client and wait for the client to retry its request. OK, but my question was: how do I *know* it actually happened? - Paul
Re: Knowing if a client disconnected?
On Aug 13, 2008, at 10:26 AM, Jerome Louvel wrote: The closest you'll find in the Restlet API is the org.restlet.service.ConnectorService class that has two callback methods: - beforeSend(Representation entity) - afterSend(Representation entity) Maybe we could introduce a new call-back method onSendError(...) that would inform you about the failed response and the reason for failure. So you're saying there's no way to know *now* with the API as it currently is? It would be nice to know *now*. - Paul
Knowing if a client disconnected?
Suppose I have a service that takes some time to compute the response to. Further suppose that a client connects but then disconnects prematurely for whatever reason either before I start or while I am returning a response. Is there any way to know if the client is really still there and connected? - Paul
Any interest in a DTO class?
I wanted a simple way to get the values of request parameters into an Object. I've implemented a DTO (Data Transfer Object) class that can be used for this. Suppose you want to implement a query request. You could do something like: public class QueryDTO extends DTO { @Required public String q; public SortOrder order; // SortOrder is enum { NAME, DATE, SIZE } public Boolean desc; QueryDTO( Request request ) throws DTOException { super( request ); if ( order == null ) order == SortOrder.NAME; if ( desc == null ) desc = Boolean.FALSE; } } What this says is that a request has 3 query parameters. Of those, q is a required String. The DTO constructor takes care of all the parsing of form data (for both APPLICATION_WWW_FORM and MULTIPART_FORM_DATA cases), enforces @Require constraints, and handles enum values. You can then use it like: public void handleGet() { try { QueryDTO dto = new QueryDTO( getRequest() ); // ... use dto.{members} as you please ... } catch ( DTOException e ) { e.setStatusOf( getResponse() ); } } DTO also correctly handles array values. For example, specifying: public String[] field; allows field to be specified more than once: http://server/foo?field=val1field=val2;... There are also @Permitted and @Forbidden annotations. For example: @Permitted( onlyIf={y} ) public Integer x; @Permitted( onlyIf={x} ) public Integer y; This will cause DTO to throw an exception if either x or y is given without the other. (@Forbidden works similarly, but in reverse.) If there's interest, I'd be willing to donate this code to Restlet. - Paul
Re: Hanging on ServerSocket.accept()
On Jul 4, 2008, at 3:57 AM, Jerome Louvel wrote: What do you mean by launching 1/10 times? I mean that the problem only manifests immediately after launch (if it manifests at all). The problem never manifests if the software has been running OK for a while (meaning it has been servicing requests). Do you stop and restart the application? Yes. Do you do this using Component#start() and stop() methods ... Yes. and differently? I don't know what you mean by that. It is important to cleanly shutdown your server connector in order to quickly release the open sockets. It's not that the server can not *bind* to the socket -- it does. (The problem I assume you are referring to is the SO_LINGER option on the socket.) It binds, listens, and does an accept -- and it hangs on the accept. Did you looked at the list of open TCP/IP sockets under Windows? You can try 'netstat -n' for example. I know the socket is open and accepting because I can telnet to the port. Both the telnet client and server hang. - Paul
Re: Series.getValues()
On Mar 23, 2008, at 10:50 AM, Jerome Louvel wrote: Paul, the Series class address the lack of a structure maintaining a list of named entries. There is no reusable Parameter class (name, value pair) in the JDK. Only the Map.EntryK,V interface comes close to it. Having just a ListParameter (via ArrayList or similar) is good but doesn't provide any facility to lookup the structure by parameter name (like the getValuesArray(name) method you were looking for). This is what the Series class adds in addition of being a ListParameter. I hope that makes sense. You can use ListParameter if you write more generic utility classes: public interface CollectionFilterT { boolean accept( T obj ); } public final class CollectionUtil { public static T CollectionT filter( CollectionT in, CollectionT out, CollectionFilterT filter ) { for ( T x : in ) if ( filter.accept( x ) ) out.add( x ); return out; } } Then you just implement CollectionFilter: public ParameterNameFilter implements CollectionFilterParameter { public ParameterNameFilter( String name ) { m_name = name; } public boolean accept( Parameter p ) { return p.getName().equals( m_name ); } private final String m_name; } Finally: ListParameter fooParams = CollectionUtil.filter( in, new LinkedListParameter, new ParameterNameFilter( foo ) ); The bonuses are: 1. The Series class doesn't leak into places that shouldn't have a dependency on it since you're using an ordinary List. 2. The solution above is completely generic and can be used for lots of other stuff. If you want, you can add other Util methods that are convenience methods to lessen typing. - Paul
Re: Series.getValues()
On Mar 22, 2008, at 4:21 AM, Stephan Koops wrote: is it necessary to use the legacy datatype array? Since when is an array a legacy datatype? (If this were C++ instead of Java, that question would have more merit.) I think never the Series deals with arrays. What about returning SeriesString? I prefer simpler APIs. Your suggestion means I have to understand what a Series is, why it's supposedly better than either an array or a Collection, and how I have to use it. In Restlet, I don't even really understand what problem all the Wrapper classes solve, never mind Series. To me, it's a lot of code one either has to maintain or learn about for very little (if any) benefit. IMHO, Restlet should be a reference implementation of REST, not an exercise in how to tweak the Java collections API. - Paul
Re: Series.getValues()
On Mar 22, 2008, at 11:16 AM, Stephan Koops wrote: Since we have java.util.List. Ok, sometime it is useful to ue arrays, but IMO in the most cases the list is the better solution. Typically you collect the result in a List, because you don't know the result size. Than you perhaps convert it to an array. So it is not faster to return arrays. The only argument for arrays are for me, that they are faster. I don't have that strong opinions on List vs. arrays. My only point was saying that Java arrays are not legacy. Series is also a List. you can handle it as List. Yes, I know. I simply don't see that Series solves any particular problem and hence why it's necessary. IMHO, it would have been simpler and cleaner just to use List directly which every Java programmers knows how to use already. - Paul
Series.getValues()
Sorry if this is a duplicate, but I never say my original message echo to the list. Begin forwarded message: Date: March 19, 2008 4:19:32 PM PDT To: discuss@restlet.tigris.org Subject: Series.getValues() This method, as written in Restlet 1.0.8, specifically this variant: getValues(String name, String separator, boolean ignoreCase) has room for improvement. Aside from the fact that the ignoreCase parameter is not used, globbing the values together with a separator is not that useful. I really want: String[] getValues(String name) with an implementation like: public String[] getFormValues( String paramName ) { final ListString temp = new LinkedListString(); for ( Parameter param : this ) if ( param.getName().equalsIgnoreCase( paramName ) ) temp.add( param.getValue() ); return temp.toArray( new String[ temp.size() ] ); } - Paul
Re: Root URIs under Windows
On Mar 10, 2008, at 1:45 AM, Thierry Boileau wrote: I've tested this code below with both Restlet 1.1 (snapshot) and Restlet 1.0.8 and it works. Could you tell us more about your code? I have my own classes derived from Directory and DirectoryResource. I override DirectoryResource.handleGet(). In handleGet(), I need to know what the Directory's root directory is so I call Directory.getRootRef().getPath(). The path it returns is URL-encoded, e.g., spaces are encoded as %20. This is why my code fails (because it needs to be decoded first). So the question is: should Reference.getPath() (and other get*() methods) return their component strings already decoded? This would parallel URI.getPath(). If you really want the original form, there's URI.getRawPath() and there could correspondingly be Reference.getRaw*() methods. - Paul
Root URIs under Windows
Does anybody use Restlet under Windows? I want my server's root URI to be a directory like: C:\Documents and Settings\pjl\My Documents\My Pictures\ That's held in a File variable. I convert that to a URI then to a String like: String rootURI = rootDir.toURI().toString(); That gives me a URI like: file:/C:/Documents%20and%20Settings/pjl/My%20Documents/My%20Pictures/ but that doesn't work. I get FileNotFound for all files. What's the right way to use Windows' directories with Restlet? - Paul
Re: Root URIs under Windows
On Mar 7, 2008, at 5:12 PM, cleverpig wrote: public Restlet createRoot(){ final String DIR_ROOT_URI=file:///E:/eclipse3.1RC3/workspace/RestletPractice/static_files/ ; Yes, I already know how to do the code. That's not my question. The differences between your example and mine are: + Yours has file:/// whereas mine has file:/ + Yours has no spaces encoded as %20. I hacked my code and made it use file:/// and it made no difference. After some more experimentation, it seems the problem is the %20 characters. To make a simpler test-case, I used a path like: C:\tmp\sub_directory When converted via File.toURI().toString(), I get: file:/C:/tmp/sub_directory and that works. When I rename sub_directory so it has a space instead: C:\tmp\sub directory I get: file:/C:/tmp/sub%20directory And this causes Restlet not to work. It seems like a bug to me. - Paul
Restlet vs. Resource
Is there a guideline when one should extend Restlet vs. extens Resource? My rationalization is that: if X represents some kind of physical resource, the one should extend Resource; if X represents some kind of service, e.g., a search service, then one should extend Restlet. Opinions? - Paul
Status class should have a Throwable field
I would like to be able to have code like: try { // ... } catch ( SomeException e ) { response.setStatus( CLIENT_ERROR_BAD_REQUEST, e ); } That is that you can pass a Throwable to setStatus() and that the Status class have the additional methods of: void setThrown( Throwable t ); Throwable getThrown(); The default implementation of the response that gets returned to the client will simply do an: t.getMessage() and include that as the textual error message. However, if I implement my own StatusService, I have full access to the exception. In my case, I'd like to return an XML entity containing an XML-ized version of the exception's stack trace. - Paul
Re: Status class should have a Throwable field
OK, fine: then simply add a constructor that takes a Throwable as well as a getThrown() method. Status can stay immutable. - Paul On Jan 26, 2008, at 1:06 PM, Stephan Koops wrote: Hello Paul, if I understood you right, than you want to add method to the class Status to save the exception in the status object. But the Status objects are immutable as all metadata. So this won't work. best regards Stephan
Re: Directory redirection issues
On Jan 21, 2008, at 1:32 PM, Jerome Louvel wrote: 1. How do I turn directory redirection off? Specifically, if the request refers to a directory and the URI doesn't end in '/', it's OK for the server to add the '/' internally for processing, but I don't want it to issue a 303 response. The problem that arise if you don't force a redirect is that all relative URIs served become harder to construct and read. For example with the /foo/bar base URI, the joe.html relative URI resolves to /foo/joe.html instead of the expected /foo/bar/ joe.html because the browser has no way to know that /foo/bar is corresponding to a directory. I understand the problem. I'm not saying don't add the '/' at the end; I'm saying have a flag that silently adds it internally without doing an explicit redirect. In the cases where you set directoryRedirection to true, mutate the Request instead to append the '/' as if you did the redirection and the client sent you back a new request with the trailing '/'. - Paul
Changing the root URI
So I create a Router, create some Directory instances with a given rootURI, and attach them to the router. At some later time, I want to change what the rootURI is globally while the server is running. In Directory, rootRef is private and there's no setRootRef() method. Why not? Similarly, Application doesn't have a setRoot() method. Why not? How can I do what I want? Right now it seems the only way would be to do something like call Router.getRoutes() and replace the list with new Directory instances. - Paul
Re: Bad implementation of Status error checking
Also, it seems that isSuccess() is wrong. In reading RFC 2616, 1xx and 3xx codes are not errors, so they should be considered success codes, no? - Paul On Jan 16, 2008, at 10:09 AM, Paul J. Lucas wrote: What if I want to make up my own Status codes? The isSuccess() and is*Error() methods do explicit code checks. Why? Why isn't the implementation for, say, isSuccess() this: return code = 200 code 300; ?
Re: Aborting request in Filter
Sorry for not commenting earlier, but Anyway, in thinking about this more, I don't think a filter should have any knowledge of its next filter. When a request is received, the engine should have a list of filters, i.e., the list itself should be external to all the filters. So, currently, you have: Request - F1 - F2 - ... - Fn I would prefer: Request - L1F1 - L2F2 - ... - LnFn where Li is a node in a linked list and the element type of the list is Filter. However, once you do that, there is no longer a need for Filter as a separate class: it's just an ordinary Restlet. Furthermore, whether a filter is before or after depends only on where it is in the list and is also not a property of a filter. (If I wanted a single instance of some filter to be both before and after, I would simply insert the same instance twice in the list at different places.) As for whether to continue upon error, each Restlet, upon insertion into the list, Restlet could have a method like: boolean acceptStatus( Status s ) { return s.isSuccess(); } Hence, the default would be to abort continuation down the list of Restlets; however, if a Restlet wants to filter error responses, it would simply override acceptStatus(). - Paul On Jan 13, 2008, at 6:51 AM, Jerome Louvel wrote: Here are the details of the change: Filter.beforeHandle() and doHandle() methods can now indicates if the processing should continue normal, go to the afterHandle() method directly or stop immediately. IMPORTANT NOTE: as it isn't possible to add a return parameter to an existing method, the change can break existing filters. In this case, you just need to return the CONTINUE constant from your method and use int as return parameter.
Re: Shutting down a server
Well, I just tried calling System.exit(0) and nothing happens: the process doesn't exit. FYI: I'm using the Simple HTTP server. There are a bunch of threads stuck in wait(). How can I shutdown the server and cause the process to exit? - Paul On Jan 9, 2008, at 11:43 PM, Paul J. Lucas wrote: When I start my server, I have: component = new Component(); // ... component.start(); To shutdown a server, I assume I do: component.stop(); However, the process doesn't stop. Should I then simply do: System.exit( 0 ); ?
Re: Aborting request in Filter
Well, if you want to post-process a request in error, you need to distinguish that case from the case where you don't want to post- process in error. Another problem is that the current doHandle() calls next.handle() and that doesn't return a boolean to indicate whether to do post- processing in error. So, even if you make doHandle() return a boolean, it's not clear what you return since it has no way to know whether it should continue (unless it checks the Status code). There's also the case where, even if you return false from beforeHandle(), you might still want to call afterHandle(), no? So if you really wanted to cover all cases, you'd have to do something like: boolean beforeSucceeded = beforeHandle( request, response ); if ( beforeSucceeded ) doHandle( request, response ); afterHandle( beforeSucceeded, request, response ); If you don't want to post-process, then the implementation of afterHandle() can check the Status code itself and do nothing on error. The added parameter of beforeSucceeded to afterHandle() would be needed to distinguish the case where beforeHandle() failed (and thus doHandle() was never called) vs. doHandle() failing. - Paul On Jan 10, 2008, at 12:08 AM, Jerome Louvel wrote: You expose a good use case. The solution below has some drawbacks because you might want to post-process a request in error, for example to add a status representation like the StatusFilter do in NRE. Even the proposed test on doHandle() could be limiting (even if it does solve your issue). Here is what I propose : let's add boolean return parameters to beforeHandle() and doHandle() that will determine whether the processing should continue with doHandle() or afterHandle() respectively. We can make this backward compatible easily and add it to 1.1 M2. How does it sounds?
Re: Shutting down a server
I switched to using Jetty and I had the same problem -- the process didn't terminate. So I figured out that it was my fault by creating a deadlock. I removed that and now the process terminates when calling System.exit(0). So then I went and tried Simple again and it too now terminates. I then tried removing the call to System.exit(0) to see if the process would exit naturally. It doesn't with Simple and does with Jetty. Hence, the bug with Simple seems confirmed. Hypothetically, if I wanted to continue to use Simple, it is OK to call System.exit(0) and still terminate gracefully? - Paul On Jan 10, 2008, at 5:31 AM, Kevin Conaway wrote: Bug the Simple developers. I am absolutely astonished that they don't provide a clean way to shut down their server. On Jan 10, 2008 2:59 AM, Paul J. Lucas [EMAIL PROTECTED] wrote: Well, I just tried calling System.exit(0) and nothing happens: the process doesn't exit. FYI: I'm using the Simple HTTP server. There are a bunch of threads stuck in wait(). How can I shutdown the server and cause the process to exit? - Paul On Jan 9, 2008, at 11:43 PM, Paul J. Lucas wrote: When I start my server, I have: component = new Component(); // ... component.start(); To shutdown a server, I assume I do: component.stop(); However, the process doesn't stop. Should I then simply do: System.exit( 0 ); ?
Re: Aborting request in Filter
By the way, in the doHandle() method, if there isn't a next Restlet, the method sets the response to CLIENT_ERROR_NOT_FOUND. Shouldn't that be SERVER_ERROR_INTERNAL because the programmer goofed by not setting a next Restlet? - Paul
Aborting request in Filter
If I write my own filter and use its beforeHandler(), I would like, upon some catastrophe, to abort the entire request and return some client error code. Unfortunately, it doesn't appear that the API for Filter allows aborting a request. True? This is another good case for using exceptions. - Paul
Shutting down a server
When I start my server, I have: component = new Component(); // ... component.start(); To shutdown a server, I assume I do: component.stop(); However, the process doesn't stop. Should I then simply do: System.exit( 0 ); ? - Paul
Re: The alphanum algorithm
On Dec 19, 2007, at 8:57 AM, Jerome Louvel wrote: However, there appear to be three authors/contributors, so we would need to get the agreement and JCA of all of them which complicates things a bit. Given the algorithm description in English, just write the code yourself from scratch and the copyright issue becomes moot. This algorithm isn't exactly rocket science. - Paul
Re: The alphanum algorithm
On Dec 19, 2007, at 11:13 AM, Rob Heittman wrote: I have concerns about doing an independent implementation because it would likely bear substantial resemblance to yours. As long as you do a clean room implementation, i.e., you'd swear under oath that you didn't look at the original code, it doesn't matter how much it resembles the original. - Paul
Limiting threads
Is it possible to limit the number of threads that Restlet uses/spawns in servicing requests? - Paul
Restlet and Flickr
Has anybody done a Flickr client using Restlet? If so, details appreciated. Or, failing that, being pointed in the right direction on how to do it (what classes to derive from) would be good. I've been looking at the Restlet code and the thing that strikes me as wrong is that the core classes have a small, finite number of authentication schemes hard-coded into them, e.g., NMTL and AWS. IMHO, there should be no authentication schemes hard-coded. There should be an interface and instead a set of bundled ones, but there's no reason, for example, why SecurityUtils should know anything about the X-Amz-Date HTTP header. - Paul
Re: Exceptions in general
On Dec 4, 2007, at 3:03 AM, Stian Soiland wrote: On 12/3/07, Paul J. Lucas [EMAIL PROTECTED] wrote: Funny, because java.io.FileNotFoundException is derived from IOException. So clearly there's precedent. Did you notice the io package name? :-) The exceptions here are about resources, not IO. So what? java.io.IOException means *any* exception with *any* I/O, be it file, socket, keyboard, courier pigeon, whatever. If RestletException were to exist, then *any* exception with *any* resource, be it a file on a local disk, or some other abstract resource, would be appropriate. Would calling it ResourceException make it make more sense to you? - Paul
Re: RESTClient
On Nov 30, 2007, at 6:05 AM, Lars Heuer wrote: RESTClient is a Java platform client application to test RESTful webservices. http://code.google.com/p/rest-client/ IMHO, command-line test tools are better because they're far more easily automated. I just write Perl script wrappers around curl. - Paul
Re: Exceptions in general
On Nov 29, 2007, at 6:30 AM, Tim Peierls wrote: However, I don't have a concrete proposal, and I don't see an easy way to do this without breaking code for 1.1m1 users. Personally, I'd prefer to break an API rather than have to live with a hacked API forever. Since Restlet is currently a 1.x API, it's presumably in its infancy. Now is the time to rework it to make it better even if it means breaking some people's code. If they don't want to upgrade, well, they have the option of not doing so. - Paul
Re: Lightweight alternative to Reference
On Nov 29, 2007, at 3:18 PM, Jerome Louvel wrote: It could have methods starting with append like the StringBuilder class, and follow the Reference naming convention. For example it could have: - appendScheme(String scheme) - appendSchemeSpecificPart(String ssp) - appendFragment(String fragment) - appendHierarchicalPart(String ssp) - appendAuthority(String authority) - appendPath(String path) - appendSegment(String segment) - appendMatrixParam(String name, String value) - appendQuery(String query) - appendQueryParam(String name, String value) Except it's not append: it's insert into the right place or set. It should force the reference to be built in the correct order so an efficient StringBuilder could be used internally and should guide the developer with clear warning messages when parts are not appended in the right order. Why should it enforce the order? The burden should be on the implementor, not the user. Don't use a StringBuilder: use simple fields: class URI { private String scheme; private String host; // ... } - Paul
Re: Lightweight alternative to Reference
On Nov 29, 2007, at 4:32 PM, Rob Heittman wrote: The warnings to the user (cough Checked Exceptions /cough) should come in when you try to confess the builder into a URI, Reference, or String and it doesn't contain enough pieces and parts to have meaning. If, as the implementor, you want to be lazy, simply use java.net.URI to do the work using the: URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment) constructor and reuse java.net.URISyntaxException as-is. (There's no need to invent another exception when the one included in the JDK will work just fine.) - Paul
Re: Lightweight alternative to Reference
On Nov 29, 2007, at 4:52 PM, Tim Peierls wrote: Abstractly, though, would you rather see ReferenceBuilderException checked or unchecked in the following: try { Reference ref = ReferenceBuilder.appendBar(myBar).appendFoo(myFoo); // do something with ref } catch (ReferenceBuilderException e) { // myBad: foo must come before bar // clean up // ? throw e; } Programmer was wrong -- this should be unchecked, right? How do you know the programmer was wrong? How does the implementor of ReferenceBuilder know whether the data was supplied by the programmer or the user of the program? If the latter, it's the user who is wrong in which case the programmer must deal with that. Therefore: checked exception. In general, IMHO, you've got to have a really, really good reason to make an exception unchecked. Because it's easier isn't a good reason. - Paul
Re: ConverterService architecture
On Nov 28, 2007, at 1:31 PM, Jason Terhune wrote: I haven't actually tried this, but couldn't you just overload the toObject() and toRepresentation() methods? Doesn't Java do the work of choosing the method with the most specific argument? For example: public class ConverterService extends ConverterService { public Foo toObject(FooRepresentation fr); public FooRepresentation toRepresentation(Foo f); } But the base class can't specify the infinite number of derived classes as arguments to an infinite number of methods. - Paul
Re: ConverterService architecture
On Nov 26, 2007, at 2:33 AM, Jerome Louvel wrote: Your suggestion regarding the map of ConverterService is interesting. However, how would you handle the reverse conversion (from Representation to Object) ? Also using a map. For both conversion directions, you allow for the possibility of subclasses, e.g.: public class ConverterServiceMap extends ConverterService { // ... public Object toObject( Representation rep ) { for ( Class c = rep.getClass(); c != Object.class; c = c.getSuperclass() ) { final ConverterService cs = m_toObjMap.get( c ); if ( cs != null ) return cs.toObject( rep ); } return super.toObject( rep ); } } Sometimes the list of available variants is closely related to the processing resource, so it may be that the Resource subclass is the best place to handle such conversions. Sometimes, yes. But other times, you could have several resources/ services that all share a common format so it would be nice to write the conversion in a single place. My vote for now is to keep ConverterService deprecated in 1.1 instead of refactoring it. :-( - Paul
ConverterService architecture
The current architecture of ConverterService is such that if I want to convert to/from an object of a given class, I subclass ConverterService. Well, what if I want to convert to/from several classes? In my subclass, I could do an: if ( obj instanceof MyClass1 ) { // ... } else if ( obj instanceof MyClass2 ) { // ... } else ... which is (a) tedious and (b) means I have to have my subclass know about lots of classes (bad design, IMHO). So instead, why doesn't Application instead have a: MapClass,ConverterService so then the code to to conversion would look up the right ConverterService based on the class of the object being converted? - Paul
Why not Reference.getQueryAsObject?
If Message.getEntityAsObject() exists, why doesn't Reference.getQueryAsObject() exist? I want to turn a query (via a Form) into an Object using a ConverterService. (I'm converting a query into an Object now, but doing it my own way since the framework apparently provides no right way of doing this.) - Paul
Re: Converting http to file scheme
On Nov 19, 2007, at 6:51 AM, Rob Heittman wrote: Or maybe Paul can figure out a way to do it without the mess. Right now, I'm still trying to get my head around all this. It's not totally clear to me when things should be a Restlet or a Resource; whether one should derive from Directory or DirectoryResource; what Helpers are exactly and when to use/derive from them. For example, in my tinkering, I tried deriving from DirectoryResource. I then attached MyResource to a router like: router.attach( /foo, MyResource.class ); The problem with that is that MyResource has no no-argument constructor (because DirecoryResource doesn't), so you get a NoSuchMethodException because the framework wants a no-argument constructor. OK, so that's not the way to do anything. For my application, I need to do 3 classes of things: simple file manipulation (create, delete, update, copy, move, i.e., WebDAV-like stuff); image manipulation (get, scale, convert, etc.); and image metadata (get, put). In all cases, I need to convert http-style URLs to local file-style URLs. Jerome mentioned that Directory does this, but it's unclear how to leverage that fact. For example, the metadata part is sort-of simple. Given a URL like: http://server/metadata/path/to/image.jpg when using GET, you should get an XML document back containing the metadata of the image rather than the image itself. I'm guessing this can be done with a Filter (?). Anyway, so it's unclear whether I'll be able to figure out how to implement COPY and MOVE without the mess. (I do have to implement *something* to do copy/move. Ideally, I'd like it to work just like WebDAV; but if I can't figure it out, I'll have to do something else.) - Paul
Implementing COPY and MOVE (Was: Converting http to file scheme)
On Nov 19, 2007, at 6:51 AM, Rob Heittman wrote: In my noodling with DAV method support, COPY and MOVE are especially challenging to implement. By extending Directory and friends, you can model a COPY as a GET and a PUT, and a MOVE as a GET, DELETE, and PUT, but this is messy, not atomic in the right ways, and not very performant. Really you need to have COPY and MOVE supported down through the client as well. This is a lot easier if you just check out trunk and hack on it, than by trying to extend everything and coerce Restlet to use the extended classes. I've figured out that to do this right, yes: you do need to extend DirectoryResource. The problem with that is that Engine insists on creating an instance of DirectoryResource and not an instance of one's derived class. So that means one has to subclass Engine and then figure out how to get engineClassName in Engine.getInstance() be one's own derived class. (Is there an easy way to do that?) Anyway, it seems like a lot of messy work. Aside: Why does Engine have a lone createDirectoryResource() method at all? It seems like overly-tight coupling. Why isn't there an easier- to-alter Factor pattern for creating directory resources? But something that would go a long way toward implementing COPY and MOVE would be simply to provide stubs for them, specifically: 1. Add COPY and MOVE to Method. 2. Add allowCopy() and allowMove() to Resource. Of course, I'm a newbie. Would doing just items 1 and 2 above be good enough to allow even a simple implementation of COPY and MOVE? - Paul
Re: Implementing COPY and MOVE
On Nov 19, 2007, at 8:12 PM, Paul J. Lucas wrote: I've figured out that to do this right, yes: you do need to extend DirectoryResource. The problem with that is that Engine insists on creating an instance of DirectoryResource and not an instance of one's derived class. So that means one has to subclass Engine and then figure out how to get engineClassName in Engine.getInstance() be one's own derived class. (Is there an easy way to do that?) Anyway, it seems like a lot of messy work. I just discovered that Directory.findTarget() is what's used to create an instance of DirectoryResource. OK, so if I derived from Directory and override findTarget(), I can return an instance of MyDirectoryResource that implements: allowCopy() allowMove() handleCopy() handleMove() I then wrote MyDirectoryResource.copyOrMove(): private void copyOrMove( boolean isMove ) { final Request request = getRequest(); final Response response = getResponse(); final String destHeader = RestletUtil.getHeaderValue( request, Destination ); final String overwrite = RestletUtil.getHeaderValue( request, Overwrite ); if ( destHeader == null || overwrite == null ) { response.setStatus( CLIENT_ERROR_BAD_REQUEST ); return; } try { new URI( destHeader ); } catch ( URISyntaxException e ) { response.setStatus( CLIENT_ERROR_BAD_REQUEST, e.getMessage() ); return; } final String serverRoot = MyServer.getServerRootDirectory(); final String sourcePath = request.getResourceRef().getRemainingPart(); final File sourceFile = new File( serverRoot + sourcePath ); if ( !sourceFile.exists() ) { response.setStatus( CLIENT_ERROR_NOT_FOUND ); return; } Status successStatus = SUCCESS_CREATED; final String id = request.getResourceRef().getBaseRef().getIdentifier(); String destPath = destHeader.substring( id.length() ); final File targetFile = new File( serverRoot + destPath ); if ( targetFile.exists() ) { if ( !overwrite.equals( T ) ) { response.setStatus( CLIENT_ERROR_PRECONDITION_FAILED, Destination already exists and Overwrite is not 'T' ); return; } if ( !targetFile.canWrite() ) { response.setStatus( CLIENT_ERROR_LOCKED, Destination can not be overwritten ); return; } successStatus = SUCCESS_NO_CONTENT; } try { FileUtil.copyFile( sourceFile, targetFile ); if ( isMove ) sourceFile.delete();// TODO: check return value response.setStatus( successStatus ); } catch ( IOException e ) { response.setStatus( SERVER_ERROR_INTERNAL, e.getMessage() ); } } This seems to work just fine. Comments? I'd prefer to leverage Directory's ability to transform an http URI into a file URI so I could easily transform destHeader into a LocalReference then call getFile() on it, but it's not clear how to do that. How does one do that? - Paul
Restlet 1.2 (Was: Easier way to get an HTTP header?)
On Nov 17, 2007, at 2:42 PM, Rob Heittman wrote: It, and other full WebDAV stuff is targeted to land in Restlet 1.2. When is 1.2 targeted to be released? - Paul
One Directory for entire tree?
I was playing around with trying to derive from Directory to implement the WebDAV COPY and MOVE methods. (How feasible is that?) One of the first things I did was to call setModifiable() based on whether the directory is actually writable (File.canWrite()). This worked fine. I then wondered about subdirectories. It seems that the single instance of Directory is used for all directories and files under the root and therefore isModifiable() returns the status of the root directory for all subdirectories and files. That seems wrong. Why isn't a new instance of Directory created for every subdirectory and file so each will return whether *it* is modifiable? Currently, if isModifiable() returns false during the handling of a DELETE method, the status is (correctly) METHOD_NOT_ALLOWED. But for all subdirectories and files, the status is (incorrectly, IMHO) INTERNAL_SERVER_ERROR. The status of METHOD_NOT_ALLOWED should be returned for *any* directory or file if it's not modifiable. - Paul
Converting http to file scheme
When a client specifies a URL like: http://server/path/to/file how do I convert that into a file URI: file://localhost/path/to/root/path/to/file ? The context is in trying to implement the Destination header for a WebDAV COPY or MOVE method. The client specifies the destination as an absolute URI. Obviously I need to map it to the local filesystem. - Paul
Easier way to get an HTTP header?
To get the value of an HTTP header, it seems as though I have to do: Form f = (Form)request.getAttributes().get( ATTRIBUTE_HEADERS ); String value = f.getFirstValue( MyHeader ); That seems rather... cumbersome. Is there an easier way? - Paul
Re: Easier way to get an HTTP header?
On Nov 17, 2007, at 2:42 PM, Rob Heittman wrote: The non-standard header mechanism is the way to go for Destination: and Overwrite: and such for the moment. By which you mean the way I've already shown in code? Or something else? - Paul
Re: New user: guidance for server?
As I mentioned, I've already read the tutorial. Perhaps I should elaborate further. I'm not ONLY managing static files. I also eventually want to have functionality for doing things like: 1. Thumbnail creation, i.e., rescale an image such that its largest dimension does not exceed N: http://server/path/to/image.jpgmaxdimension=100 2. Image format conversion, e.g. original image is Canon RAW, client wants JPEG: http://server/path/to/image.cr2format=jpeg 3. Caching of items 1 2. Regarding the suggestion to look at the Directory class, if I wanted to provide directory listings in XML, I assume then that I could derive from it and override getIndexRepresentation() and getIndexVariants(), yes? - Paul On Nov 15, 2007, at 11:02 AM, Rob Heittman wrote: I think this is what you want: http://www.restlet.org/documentation/1.0/tutorial#part06 - Original Message - From: Paul J. Lucas [EMAIL PROTECTED] To: discuss@restlet.tigris.org Sent: Thursday, November 15, 2007 1:05:56 PM (GMT-0500) America/ New_York Subject: New user: guidance for server? Hi - I'm new to Restlet. I want to create a simple server that serves the contents of directories and images in those directories. URLs would be as you would expect: * Get contents of directory: http://server/path/to/dir/ * Get image in directory: http://server/path/to/dir/image.jpg Additionally, clients would be able to create and delete new directories and images therein. I've read the tutorial, looked at sample code, and even read the O'Reilly book, but it's still not clear what the right approach is. One way is to have an ImageService class derived from Restlet and attach this to the server's default host. Another way is to have an ImageResource class service derived from Resource and attach this to a Router. It's not clear to me which is the right way of doing what I want. Any guidance would be appreciated. Thanks. - Paul