Sousa Devel Notes v2
See also Early Sousa Devel Notes - 2007
March 1, 2008
It is time to return to the Sequencer tool and bring it up to the level coding in the Page tool. After that, a release is in order, though I might sneak in a few more media types.
One of the things I want to change about the Sequencer tool is the reliance on a fixed directory to hold sequences. They should be able to live anywhere and now that I've determined that I create my own media types in the CHS, there's no need to restrict them to a special place. Mostly, this means changing MainProducer, which I am thinking of replacing with SequenceProducer – the name seems a bit more expressive than "Main".
Added sousa.util dependency to Sequencer Maven project. This will bring in the shared UI code.
Removed unused producers and view parameters including:
- EditPageProducer
- EditPageViewParameters
- EditTileProducer
- EditTileViewParameters
- NewPageProducer
- NewPageViewParameters
Created a sequence icon (sequence.gif) and added it to sousa-seq-tool.
For some reason (could it be a bug?) the new sequence icon is not showing in the MainProducer view. What ever the problem, I don't think it worked before, either. I restored the original URL and it still doesn't work. The problem was with the template. A wrapping tag was used for the link, which overrode the img tag (a link) inside of it. My moving the image outside, got it to work.
Created SequenceProducer and SequenceParameters to replace MainProducer and MainViewParameters. This is the first step towards making sequences live anywhere.
SequenceProducer has a view id of "sequence", which means that a new template must be created (based on the page template). Complies ok, but by moving the DefaultView from MainProducer to SequenceProducer, I'm sure is VERY broken.
Created a sequence.html template by copying main.
Added SequenceProducer.java, SequenceParameters.java, and sequence.html to SVN.
Started converting over to EditEvent action constants in SequenceProducer.
Started the process of merging code cover from PageObjectProducer to SequenceProducer. Copied page.html content into sequence.html.
The bulk of the logic in fillResources() is commented out due to all the links off to other views.
Things are compiling without error. Fired Sakai up and checked the sequence tool. It comes up with out error. No real content since I stubbed out fillResources(). But by carefully adding that code back in, I should get the sequencer select to work again.
Next Steps
- Add custom sequence icons to home select page. - done
- Remove unused views in Sequence tool. - done
- Allow sequences to be created anywhere. - in progress
- Use EditEvent action constants in sequence code.
- Create sequences using media type of "sousa/linear-seq"
- Update the Sequence tool to use the EditChainService.
- Update the Sequence tool to use content handlers, etc.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Enable CHS to launch a page into the page viewer.
- Add CHS action to edit a page view (layout).
- Look into enabling Entity Broker
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 2, 2008
Enabled the logic in SequenceProducer.fillResources(), but commented out links to playing the sequence, adding new sequence, and delete sequence.
Compiled, works but no resources are displayed. Can drill down into folders. The first thing to get working is play sequence.
Added the link to the player. Temporarily changed definition of sequence to be "text/xml" so that I can test it.
Something strange. I changed isViewable() to isSequence() in the resource display block, but when I ran the code, the collections below the root disappeared.
Found the problem. I changed the template rsf:id to play-link while the collections were expecting add-link. Changed all to item link.
Can now link to player. Fixed return in PlaySequenceProducer. Also changed over to EditEvent constants.
Next Steps
- Allow sequences to be created anywhere. - in progress
- Create SequenceProducer and SequenceParameters - done
- Show folders and drill down - done
- Play sequence and return to SequenceProducer. - done
- Create new sequence and return to SequenceProducer.
- Edit sequence and return to SequenceProducer.
- Delete sequence.
- Use EditEvent action constants in sequence code.
- Create sequences using media type of "sousa/linear-seq"
- Update the Sequence tool to use the EditChainService.
- Update the Sequence tool to use content handlers, etc.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 3, 2008
Call away to road side emergency very late last night (no injuries, but annoying). While waiting for tow truck, I gave some thought Sousa design issues. These are reflected in Sousa Design and Sousa Learning Design and reflect thoughts on templating, branching sequences, and editing parameters.
Today, I'm working on getting the edit sequence and delete sequence links to work. Pretty much eliminated edit action events in view parameter files.
Confirmed that delete is working. Confirmed that editing is working.
That only leaves create new sequence. This may take some code changes, since the idea is to be able to create a sequence in any collection.
Link out to new sequence works. Able to edit, but update doesn't create new sequence.
Next Steps
- Allow sequences to be created anywhere. - in progress
- Create SequenceProducer and SequenceParameters - done
- Show folders and drill down - done
- Play sequence and return to SequenceProducer. - done
- Create new sequence and return to SequenceProducer.
- Edit sequence and return to SequenceProducer.
- Delete sequence. - done
- Use EditEvent action constants in sequence code. - done
- Create sequences using media type of "sousa/linear-seq"
- Update the Sequence tool to use the EditChainService.
- Update the Sequence tool to use content handlers, etc.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 4, 2008
Started work on creating sequences in any collection. Added link to folders. Created NewSeqParameters to pass collection id. Added code to NewSeqProducer to pass collection id through to EditSeqProducer. Added a collection id to the Sequence object. Created a new constructor to take name, desc, collId. Modified SequencerService.createSequence to take name, desc, collId. Modified creation of the Sequence object to take collection id.
All of the code is in place at this point. I'm trying to decide to tackle the EditChain update as well before testing. I should do this one thing at a time, but the creation and saving of sequence is kinda screwed up. I'm going to test that editing is ok, then update to the new EditChain mechanism. Once edit is ok, I can come back and fixe save/creation.
Added code to EditSeqProducer to cache the sequence and create an edit chain using the EditChainService. On edits, fetch sequence, make a copy, and apply edits from edit chain. Compilied code and ran it. Edit seems to still work ok. However, I get an exception when I try to create a new sequence. A simple problem with the wrong view parameter object being used to access the collection id. Fixed. Editing now works on a new sequence as well. All that's left is to get the save operation working for both existing and new sequences.
Collection id is not getting passed through to the EditSeqProducer from NewSeqProducer. This causes sequence.save() to crash at update time. I had created a hidden field in the New Sequence form. RSF handles this, so there is no need for me to do it explicitly. Didn't fix the problem. It turned out to be uninitialized in the sequence constructor.
Sequence was constructed, presumably with new type. However, it doesn't show up in the collection where it was created. It does show in the Resources tool, however. This is likely a media type / display problem. It's close to working. Editing existing sequences works. Changes are saved.
See some problems with cached sequence. When I try to edit a sequence, I'm seeing the previously created sequence. This happens in both new and existing sequences.
It's not the cached sequence that's the problem, it's the edit chain. It's not getting deleted after the previous editing.
Looks like the problem was using the wrong chain id to delete the edit chains on save. Yep. That fixed it. Edit full works now.
Changed isSequence() to test on "sousa/linear-seq". Sequences are now appearing in the collections they were created in. Sequences in "Content Sequences" are no longer visible (and should be deleted). This whole directory is no longer needed.
checked code into SVN.
Most of the major work in the Sequence tool is done now. The only remaining bit is to convert code to use content handers.
Added content handlers to EditSeqProducer, AddItemProducer, and PlayProducer. Added grid.gif and no_thumb.gif. Modified templates to agree with conventions.
Tested all - all work.
Next Steps
- Allow sequences to be created anywhere. - done
- Create new sequence and return to SequenceProducer. - done
- Create in any collection. - done
- Edit sequence and return to SequenceProducer. - done
- Create sequences using media type of "sousa/linear-seq" - done
- Update the Sequence tool to use the EditChainService. - done
- Update the Sequence tool to use content handlers, etc. - done
- Sequence edit page - done
- Add item page = done
- Sequence player page - done
- Remove deprecated methods in SequencerService, including support for EditChains there.
- Filter unsupported items for selection in AddItemProducer (both sequence and page). XML files and sequences should be filter, at least.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 5, 2008
Lot's of progress yesterday.
Added code to filter selections by adding ContentElementHandler.isSupported(), which checks to see if the content type of an element is currently handled. Added this test to both version of AddItemProducer (page and sequence tools). Works.
Started code clean up. Deleted MainProducer and MainViewParameters, which broke several references all needing to be fixed.
Deleted main.html, newpage.html, page.html, and addpage.html. These templates are not needed.
Removed Edit chain code from SequencerService. Methods included createEditChain(), getEditChain(), and clearEditChain().
Removed MainProducer bean definition from requestContext.xml.
Tested both tools. Both seem to work fine.
Had a quick look canceling out of add item in the page tool. Code and template is there. Must be something minor wrong with it. The Page tool has a cancel link that works. The problem is in the Sequence tool. While you can cancel out, the event isn't handled in EditSeqProducer. It tries to do an edit and gets a null pointer error. I also had to add an EditViewParameter object with a Cancel operation in AddItemProducer on the cancel link. Works now.
Check into SVN. Revision 46340. Made backup.
I'd like to document the process of adding a new media type to Sousa. The Resource tool supports a URL object that might be a good candidate. I need to figure out what media type it is, though. The following line in AddItemProducer (in the Page tool) can be enabled to see all media types going by:
System.out.println ("***** AddItemProducer - item ["+ name + "] has media type of ["+ type + "]");
This is a useful tool when trying to figure out media types. The above returns:
***** AddItemProducer - item [Nolaria.com] has media type of [text/url]
Thus we learn that the item "Nolaria.com" has a media type of "text/url".
Documentation is being put into [ Adding New Content Elements].
A CEUrl class was created to handle this new content element.
Coded and compiles, but not tested yet.
All told, it probably took about 30 minutes to add the type, though this took much longer because I was documenting the process as I went.
The URL element doesn't quite work fully. It shows up for selection. The thumbnail shows in EditTileProducer after being selected. When I update the tile, the framed URL is shown in EditPageProducer. However, the "Update" and "Cancel" links at the bottom of the page are missing. I figured this might be a template problem, but it doesn't seem to be working.
Next Steps
- Filter unsupported items for selection in AddItemProducer (both sequence and page). XML files and sequences should be filter, at least. - done
- Remove deprecated methods in SequencerService, including support for EditChains there. - done
- Cancel out of AddItemProducer in Sequence tool. - done
- HTML link media type.
- Video media type.
- Audio media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 6, 2008
It occurred to me last night that I could fix CEUrl by using UIVerbatim until RSF is fixed.
Made some notes about video and audio thumbnails in Content Notes.
Modified the HTML rendering to use the following code until RSF is fixed:
// The following hack is being used due to a problem with RSF and Firefox. RSF converts an IFRAME with closing // tag into an empty block. Firefox requires IFRAME to have a separate closing tag. String content = "<iframe height=\"600\" width=\"600\" src=\""+url+"\">This browser does not support iFrames.</iframe>"; UIVerbatim.make(tofill, id, content);
Spoke to Antranig briefly about this problem. He says it cannot happen, so he will have to write a small test case and see if it fails for him and why.
Meanwhile, the above hack seems to work just fine. Pages containing a framed website can be created.
Started working towards support for video and audio. Found an AVI clip of Megan with the Sakaiger in Amsterdam. Uploaded it, but I don't think the Resource tool recognizes it as video. It shows a generic icon. Editing the details shows it to be of type " video/avi", however. That should suffice for my purposes.
I'm going to hunt around for more clips and examples. Different kinds of video formats would be good to test. Found three different kinds of video files: AVI, MPG, and WMV. Created CEVideo and CEAudio handlers. Registered, but stubbed out content developed with a text message. Thumbnails will show descriptions, eventually.
Added the embeded tag to view.html, play.html, and editpage.html. Added code to generate the embedded controller for audio and video. The AVI and MPG video both play. The WMV shows controls, but doesn't play, even when you hit the button. Some kind of bug there.
Checked code in. Revision 46409.
Next Steps
- HTML link media type. - done
- Video media type. - done
- Audio media type. - done
- Bug: should be able to select the new content elements from top level of Page tool for viewing - without being in a page object. - done
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 7, 2008
Start work on content and parameter editing. Two new views will be required: NewItemProducer and EditItemProducer. I though I might have to have choice view to choose between creating an item and a page, but I think I'll just add two links in PageObjectProducer.
Created newitem.html for the new item view. It will have the same fields as new page, but also have a menu to select what kind of item to create.
Created NewItemParameters.java.
Created NewItemProducer.java.
Need to add these to SVN tree.
Next Steps
- Editing properties and content.
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 10, 2008
Added new files to SVN.
Created EditItemProducer.java, EditItemParameters.java, and edititem.html.
Added them to SVN.
Added link to PageObjectProducer to NewItemProducer.
Added form link from NewItemProducer to EditItemProducer.
Added to SVN.
Edited NewItemProducer to contain a dummy selection menu. This needs to be generated from ContentElementHandler somehow.
Stubbed out the EditItemproducer page with some text.
Modified EditItemParameters to include id, op, and type. Type is only used if a new item is being created.
Next Steps
- Editing properties and content. - in progress
- Add NewItemProducer - done
- Link to NewItemProducer from PageObject. = done
- Add EditItemProducer - done
- Add EditItemParameters - done
- Link from NewItemProducer to EditItemProducer - done
- isEditedable() methods on content element handlers.
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- getName() on handlers
- getType() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 11, 2008
Currently the design of editing provides two entry points: editing an existing content item and creating one in a directory. The first goes directly to EditItemProducer, while the second goes to NewItemProducer and then to EditItemProducer. The question is where are the edits saved? My first thought was that they'd be saved in PageObjectProducer, since that's where the user needs to return to, once an item is created or edited. However, this greatly complicates the PageObjectParameters. Last night the idea of a preview page occurred to me. Kicking on a save link in EditItemProducer would take the user to a PreviewProducer where the completed item would be shown. From their, the user can press "save" and go to PageObjectProducer, "edit" and go back to EditItemProducer, or "cancel" and go to PageObjectProducer with no save.
There are some advantages to this approach. First off, the user can see what affect changes to parameters will have on the displayed item. Sizing of images, for example. Secondly, the parameters can be bundled up along with a reference id and media type WITHOUT actually creating the content resource. Nothing to clean up if the user cancel's out (or navigates away from the page). This bundle would be saved to the session state and neatly picked up by the PageObjectProducer for final resolution.
Continued work on ContenElementHandler methods getTypes() and getNames(). These will be used to build the selection menu in NewItemProducer.
Next Steps
- Editing properties and content. - in progress
- isEditedable() methods on content element handlers.
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- getName() on handlers
- getType() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 12, 2008
Added getHandlers() to ContentElementHandler.
Added isEditable() to ContentElement, CEBase, and all handler classes.
Added code to build option and value arrays in NewItemProducer based on the isEditable() flag.
Originally I coded the NewItemProducer to create an array of options and values based on isEditable(), but I decided that this isn't necessary. Instead, the type selection should include all supported content elements, since any can be created. Later, in EditItemProducer, the content and parameter forms will be optionally included based on whether they are supported or not.
isEditable() may not be needed and probably should be backed out of all classes. Instead, I will need a isContentEditable() and isParametersEditable() booleans.
Well, the menu works, but unfortunately it includes the page object handler, too. I may need to provide some sort of list(s) filtered by atomic items, or items that can be simply edited. Heck, I may need to abandon this approach completely if I end up with a lot of custom editors.
Next Steps
- Editing properties and content. - in progress
- isEditedable() methods on content element handlers. - done
- getName() on handlers - done
- getType() on handlers - done
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 13, 2008
It seems likely to me that there will be more than one complex editor in the Page tool in the future, beyond the grid layout editor supported now. For example, any item that requires a form response (like quiz questions or problems). That being the case, I need a filter to see if the content element is simple, ie, doesn't require programmatic editing support. I'll convert isEditable() to isSimple(). Changes done. Changed construction of select element in NewIemProducer. Now produces a drop down list of content types that exclude grid pages and structured text.
Starting work on EditItemProducer. A new object is needed to bundle information about a content item that's being edited or created. If edited, then it has a ContentResource. If new, then we know it's collection id, name, and description.
There is a convention around creating identifiers for content resources. If it's a file, the name of the file is used in the identifier. This eases URL creation, I believe.
From looking at the code, it looks like I can use the Item object to bundle information about the content item. After all, it's used for pretty much the same purpose in a sequence. All that's needed are some minor tweaks in the implementation to cache a ContentResource (if it's being edited). A new Item creation method will also be needed in SequencerService. Added. Fixed up code in ItemImpl so that it doesn't assume that a content resource exists for it.
Ready to code up EditItemProducer.
Next Steps
- Editing properties and content. - in progress
- isEditedable() methods on content element handlers. - done
- getName() on handlers - done
- getType() on handlers - done
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 14, 2008
Checked in previous work. SVN Rev. 46743
Added code to PageObjectView to add an edit link to content items if they are "simple".
Modified EditItemProducer to create an Item on NEW or EDIT. From this, the title and description are shown.
Now that I see these two appearing in the view, I realize that users will want to edit these as well.
After some amount of thrashing, got the cancel link to display and work.
Added isParametersEditable() and isContentEditable() flags to all handlers.
Put in stubs for edit content and edit parameter form elements. Stubs work just fine.
Started work on editParameters() in the content handlers. Focusing on images first, because their parameters are simple.
Got the basics of editParameters() working. Stubbed out methods in all content handlers and implemented a pair of parameters for CEImage - height and width. Here's a picture:
This works by using an out of band agreement between the template and the editParameters() implementation for that content element. The template looks like this:
<form method="#" rsf:id="edit-form"> <table border="0" cellpadding="2"> <tr> <td align="right"><span rsf:id="edit-name-label">Name label here.</span></td> <td align="left"><input rsf:id="edit-item-name" type="text" name="name" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-desc-label">Description label here.</span></td> <td align="left"><input rsf:id="edit-item-desc" type="text" name="desc" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label">Parameter 0:.</span></td> <td align="left"><input rsf:id="edit-input" type="text" name="content" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p0">Parameter 0:.</span></td> <td align="left"><input rsf:id="edit-input-p0" type="text" name="p0" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p1">Parameter 1:.</span></td> <td align="left"><input rsf:id="edit-input-p1" type="text" name="p1" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p2">Parameter 2:.</span></td> <td align="left"><input rsf:id="edit-input-p2" type="text" name="p2" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p3">Parameter 3:.</span></td> <td align="left"><input rsf:id="edit-input-p3" type="text" name="p3" size="40"/></td> </tr> </table> <input rsf:id="edit-item-submit" type="submit"/> <a rsf:id="cancel-link"><span rsf:id="st-cancel-name">Cancel Link</span></a><br/> </form>
The form has input elements for up to four parameters (we may need as many as eight, but four is good for now). The handler doesn't use them, they don't show up in the UI view. There are inputs to edit the name and description. These are created in EditItemProducer. This is followed by a single field for content editing (not implemented yet). The come the four parameter fields. What parameters are handled by what fields is another agreement, this time between editParameters() and saveParameters() - to be implemented. At the moment, the code doesn't retrieve existing values, but that shouldn't be hard.
I think I'm going to need some kind of extension to the Item object as well. It needs to hold temporary values until everything is finally saved. It will have space for temporary parameter values, changed names and descriptions, content, etc. Previewing modified content before saving will be a challenge.
Next Steps
- Editing properties and content. - in progress
- isParametersEditable() on handlers - done
- isContentEditable() on parameters - done
- editParameters() on handlers - done
- saveParameters() on handlers
- Get edit parameters to work - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Preview edit changes
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar.15, 2008
Created PreviewItemProducer, PreviewItemParameteters, and preview.html.
Added these to SVN.
Edited PreviewItemProducer to show stubbed title.
Edite PreviewParamters to hande these fields: name, desc, content, p0, p1, p2, p3.
Changed EditItemProducer to refer to PreviewItemProducer in the form.
Form now links to stubbed PreviewItemPage.
Item currently has the following object variables:
private String resourceId = null; private String name = null; private String type = null; private String description = null; private Layout layout = null;
In addition to these, we're going to need the following in an EditItem class:
private String collectionId = null; private String content = null; private String p0 = null; private String p1 = null; private Layout p2 = null; private Layout p3 = null;
Created EditItem (API) and EditItemImpl.
Implemented both. Added both to SVN.
Created SequencerService.createEditItem() in two flavors (edit and new).
Added saveParameters() to content element handlers.
Added code to PreviewItemProducer to call saveParameters().
Compiles, needs to be tested. Implement save image parameters.
Implemented preview - image shows in preview page. It was pretty simple, just needed to prune down the ViewPageProducer logic, since this won't ever show a Sousa page.
Now I need to add parameters to content images display. This could be a bit tricky, since the properties are not stored out to the resource in preview. I might be able to use instanceOf to detect an EditImage being passed into displayContent(), then pick up the local values instead of the stored values.
Next Steps
- Editing properties and content. - in progress
- saveParameters() on handlers - done
- Get edit image parameters to work - done
- Preview edit changes - done
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Save parameter changes
- Implement parameters in remaining content handers (besides image).
- Show parameters in displayContent() handlers.
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 16, 2008
Started work on using parameters in preview image. I think the saveParameter() is misnmaed, because I'm going to need to actually save parameters back to the ContentResource later. Perhaps something like catchParameters(). Something similar will be needed for content as well. This is turning to be a bit more complicated than I originally envisioned. It will work, but somehow, it should be simpler.
Defined constant key names in ContentElement.
Finished coding of parameter inclusion in CEImage.displayContent().
Some kind of problem with the say I am decorating the RSF component. It rendered as:
<img width="null" height="null" src="http://localhost:8080/access/content/group/ContentTest/Aikido/seminar.jpg"/>
Heh. I didn't implement saveParameters(). Duh.
Breakdown. The saveParameter() method takes a ViewParameters() object, which I was going to up-cast into PreviewParameters. Doing so would create a dependency on sousa-page-tool, which I don't really want. I'd like for this UI code to be completely independent of any tools, though it is tied to them by conventions and protocols.
Sometimes, all you have to do is walk away from the code and things get better. Over dinner, I realized that I don't need to call saveParameters() in PreviewProducer. Just make sure all the values get into the EditItem object. This can be done without a priori knowledge of what parameters are supported for a particular content item. Just copy them all! Even empty values. They are all there, so why not? Then, when it comes time to either display or save them, the specific content handler will know which ones are good and where they belong.
Image now previews with parameters.
Next Steps
- Editing properties and content. - in progress
- Implement parameters in remaining content handers (besides image). - done
- Re-edit parameters
- Save parameter changes
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Show parameters in displayContent() handlers.
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 17, 2008
Implemented Change (re-edit). Works fine. Some modifications to the template.
Implemented Cancel. Works, goes back to PageObjectProducer with folders open – nice touch! I have to add that on all cancels.
This leaves saving the EditItem and clean up of cached objects.
Changed saveParameters() on all handlers to only take an EditItem as an argument. That's all that's needed.
Everything is in place to save objects, but the implementation in CEImage (etc). There is a bit of a catch to handle, since if there is not ContentResource in place (the create item case), then we can't update / initialize parameters (properties).
Created save() and saveParameter() methods in EditItem. This greatly simplifies adding content handler, since the content resource will be created if not present, then the parameters can be saved out to statically defined property names. CEImage.saveParameters() is implemented as follows:
public void saveParameters(EditItem item) { item.saveParameter (ContentElement.PARAM_HEIGHT, item.getP0()); item.saveParameter (ContentElement.PARAM_WIDTH, item.getP1()); }
This will the pattern for all saveParameter() methods in content handlers.
Need to implement EditItem.save() and EditItem.saveParameter() and all will work.
I have implemented the code needed to save resources out into content resource properties IF the resource already exists (this is the edit case). If the content resource doesn't exist, edits are lost (thrown away). Code tested and works! Scaled a picture to 50% of it's regular size. Shows up as 50% in page viewer.
Some additional instructions and tips will benefit the user. I might add a short instruction line at the top of the parameters block in EditItemProducer, and a tips column, too. Moved height and width labels off into the message bundle. Implemented tips and added height and width tips to the message bundle.
Implemented the border parameter in CEImage.
Fixed setup of edit parameter forms to pull old values into the form. Added getProperty() to EditItem.
There is a problem with the border attirbute. It doesn't show up in the preview or view. I think it be a problem with style sheets. My books indicate that the border attirbute is deprecated in favor a style, but it's still implemented in Firefox (etc.).
Next Steps
- Editing properties and content. - in progress
- Re-edit parameters (change) - done
- Add parameter tips. - done
- Save parameter changes - done
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 18, 2008
Couldn't figure out what the problem with borders on images was. Tried to render it as a style, but that didn't work. Dropped it from the code, desupporting borders as a parameter.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 19, 2008
Had a Chat with Antranig on Mar. 19, 2008 on file upload.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 24, 2008
In order to create new content items via Sousa, I'm going to have to support file upload. In order to do an upload, I need to use a POST form. RSF uses the Spring file upload resolvers and there is an example on the RSF site. This is documented in a Chat with Antranig on Mar. 19, 2008.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
Mar. 25, 2008
Downloaded the TestRSFComponents example.
The file upload form has to be set up as a POST form with a multipart encoding:
<form rsf:id="basic-form" method="post" enctype="multipart/form-data"> <input type="file" name="fileupload" /><br/> </form>
(This comes from the example in an edited form) It's interesting to note that the file input field doesn't have to be generated by RSF, as long as the field name is reflected in the view parameters. This is likely so because this field is never initialized, unlike text or select fields.
In the Sousa Page tool, the form is displayed in EditItemProducer and the submit action is handled by PreviewProducer. As such, it is PrevewProducer that will have to be wired up to extract the uploaded file from the multi-part enclosure and save it out to some kind of temporary file on the server.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
Apr. 3, 2008
Time to tackle content editing starting with file upload. Gonna need to add a couple more methods to ContentElement:
public void editContent(UIContainer tofill, String templateIdBase, EditItem contentItem); public void saveContent(EditItem item);
These parameters may not be right. Stubs added to all content handlers and compile.
I'm going to push the "New Item" path using video as the test case. I've got a clip of Megan May with the Sakaiger to use.
Changed the edititem.html template to use POST instead of GET. This is necessary to support file upload:
<form rsf:id="edit-form" method="post" enctype="multipart/form-data"> <table border="0" cellpadding="2"> ... Name and description fields go here ... <tr> <td align="right"><span rsf:id="edit-label">Content:</span></td> <td colspan="2" align="left"> <input rsf:id="edit-input-text" type="text" name="content" size="60"/> <input rsf:id="edit-input-file" type="file" name="content" size="60"/> </td> </tr> ... Parameter fields go here .... </table> </form>
Note that there are two flavors of content input at this time: text and file. Since only one or the other can be used, I think I can get way with using the same name (content). Later, other kinds of input might be used here such as textarea or a structured text editor. That can be worked out later.
Added editContent() and saveContent to ContentElementHandler. The following screen results from starting the creation of a new video item in a folder:
That was pretty easy. Now for the hard part. I need to add support for the multi-part enclosure resolver. RSF uses the resolver that comes with Spring and there is an example (see above). It should just be a matter of following the example. Things are never that easy, however. For starters, this is the only POST operation in all of Sousa. I'm not sure how it will affect state and use of back button. Generally, you can't use the back button to go back past a POST operation, but who knows? Antranig is a genius. Maybe he fixed that.
Confirmed that editing of parameters still works. That's good news.
Besides setting up the multi-part resolver, the file upload demo defines an action handler for submit:
UICommand.make(form, "submitfile", "#{uploadaction.submit}");
"uploadaction" is a bean defined in the request scope file. Although the code isn't very clear, it looks like the parts of the submit are made available to the action handler as a map, presumably keyed by field names. The EditItem should be cached in the user's session, so it's possible to collect the edited content as it comes in, and save it off there. However, leaving large objects (like a video file, for example) in memory is NOT encouraged by Sakai. It needs to be moved out of memory into some form of temporary storage. Too bad CHS doesn't have explicit support for temporary files. I think I'm going to file a Jira request for this ( - SAK-13320Getting issue details... STATUS ).
Created UploadBean.java based on the bean included in the RSF example. This will handled the submit action. The UploadBean should come into scope when the request-response is being processed. As such, it should be available to the producer when it comes time to fill the component tree. It's going to need some careful Spring wiring. The multi-part map takes the place of the ViewParameters object. This is still present, but is not being used to resolve request parameters. They should all be in the map.
I note in the example that the upload bean is injected into the ResultsProducer. This means that whatever is extracted from the forms submission can be present in this bean and made available to show results.
Jim Eng on Temporary Resources
Look at the citations helper:
Find the implementation of the method with this signature:
protected ContentResource createTemporaryResource(ResourceToolActionPipe pipe)
The ContentEntity in the pipe is the collection in which the CitationList is being created. The temporary resource is created there. If the user's session is lost before they are done creating the Citation List, the temporary resource will be there named "New Citation List" or "New Citation List-1" or "New Citation List-2" or whatever, so the user can recover work they've done. Notice that we tried to hide it. There are problems with that.
The temporary resource is deleted if the user clicks "continue" or "cancel" while in the citation helper. You can see where that's done by searching for the doFinish and doCancel methods (or by searching for "removeResource").
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
Apr. 4, 2008
Added bean definition for UploadBean. All the bean does is print out a message to stdout at this point. I just want to see if it is getting invoked correctly. Display logic in PreviewProducer has been commented out.
Well, it transitions to the preview page with no errors, but it doesn't look like the submit action was invoked.
Re-started tomcat. I didn't see any Sousa-related errors go by.
This might be part of the problem. Here is the render HTML for EditItemProducer:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/preview" enctype="multipart/form-data" method="get">
Note that the method has been changed to GET.
It looks like I may have coded the UIForm in EditItemProducer. It still refers to a ViewParameters object, which explains why that appoach still seems to work. I also note that text can be uploaded into the action handler by associating an EL string with the UIInput. That could be how other parameters are handled.
Ok, this looks better:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/edititem" enctype="multipart/form-data" method="post"> <input type="hidden" name="op" value="new" /> <input type="hidden" name="type" value="video" /> <input type="hidden" name="name" value="Sakaiger" /> <input type="hidden" name="desc" value="Megan with Sakaiger" /> <input type="hidden" name="id" value="/group/ContentTest/Some Stuff/" /> ...
Ok, I got an error when I tried to sumbit the form:
2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key Fast track action value uploadaction.submit> 2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key name value Sakaiger> 2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key desc value Megan with Sakaiger> 2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key edit-item-name value Sakaiger> 2008-04-04 11:45:35,727 WARN (RSFActionHandler.java:213) - <Error invoking action> Target exception of class java.lang.SecurityException Successive lines until stack trace show causes progressing to exception site: Error invoking action --> Writing to path content is not permissible - make sure to mark this path as request addressible - http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=RequestWriteableBean java.lang.SecurityException at uk.org.ponder.mapping.DARApplier.checkAccess(DARApplier.java:116) at uk.org.ponder.mapping.DARApplier.applyAlteration(DARApplier.java:384) at uk.org.ponder.mapping.DARApplier.applyAlterations(DARApplier.java:458) at uk.org.ponder.rsf.state.RSVCApplier.applyAlterations(RSVCApplier.java:82)
It seems very strange that I'd get a security violation error from the Wiki Tool.
Looking back at the two rendered forms above, I note that one has a "preview" page while the more recent one designates "edititem" as the target page. Perhaps the existing page is assumed.
Changing the ViewParameters even to a SimpleViewParameters causes the method to change back to GET, even though the action is now right:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/preview" enctype="multipart/form-data" method="get">
I need to do some more research on POST forms in RSF, obviously.
Here's an interesting piece of information from UICommand:
You may NOT set the (navigation) target of a UICommand, by RSF design it will ALWAYS (in the case of an HTTP/HTML render system) post to the same URL as the page on which it is contained.
That certainly explains why it wants to go to the edititem template - though not why I got a security error.
This will require re-thinking the state diagram and flow of information in editing.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers - done
- saveContent() on handlers - done
- Get file upload to work.
- Get edit content to work.
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Finish VRML media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
April 7, 2008
Had a [ Chat with Antranig April 8, 2008] on POST forms in RSF. The upshot of the discussion is that I need to create an register a NavigationCase to forward the results of the file upload form to PreviewProducer. The documentation on RSFwiki is pretty clear. I register a navigation case and then return a string out of my action handler. This causes the registered producer to be invoked as if a GET request had been made. I may even be able to pick results out of a ViewParameters object. Consider this snip from the NavigationCase documentation on RSFwiki:
public List reportNavigationCases() { List l = new ArrayList(); l.add(new NavigationCase("added", new SimpleViewParameters( ItemsProducer.VIEW_ID))); return l; }
I could just as easily register a PreviewParameters object instead of a SimpleViewParameters, I would think.
FCKEdit and TinyMCE controllers may require the use of a POST form, too, since the text may be arbitrarily long.
April 20, 2008
A closer look at the file upload demo indicates that each field in the form is going need it's own variable in the action handler bean. The text field in the example does, though the file field doesn't, it relies on the submit action and a map created.
There really isn't a lot going on here, that I can see. The text fields are stuffed into bean variables, including the one indicated by a select control.
The ViewParameters passed into EditItemProducer may likely be causing a problem, especially on subsequent transactions. This may be responsible for the fossilized fields showing up in the rendered HTML source.
One strategy that might be workable is to convert the NewItem template into a POST. Then handle the submit folding it into an EditItem object held in the session state, then use a Navigation Case to forward control to EditItemProducer. This might eliminate the need for a ViewParameters object coming into EditItem.
Here is the key part of the rendered HTML of edititem:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/edititem" enctype="multipart/form-data" method="post"><input type="hidden" name="op" value="new" /> <input type="hidden" name="type" value="video" /> <input type="hidden" name="name" value="Sakaiger" /> <input type="hidden" name="desc" value="Megan with sakaiger" /> <input type="hidden" name="id" value="/group/ContentTest/Some Stuff/" /> <table border="0" cellpadding="2"> <tr > <td align="right"><span >Name:</span></td> <td colspan="2" align="left"> <input value="Sakaiger" type="text" size="60" name="edit-item-name"/><input type="hidden" name="edit-item-name-fossil" value="istring#{name}Sakaiger" /> </td> </tr> <tr > <td align="right"><span >Description:</span></td> <td colspan="2" align="left"> <input value="Megan with sakaiger" type="text" size="60" name="edit-item-desc"/><input type="hidden" name="edit-item-desc-fossil" value="istring#{desc}Megan with sakaiger" /> </td> </tr> <tr > <td align="right"><span >Select a video file to upload:</span></td> <td colspan="2" align="left"> <input value="" type="file" size="60" name="edit-input-file"/><input type="hidden" name="edit-input-file-fossil" value="istring#{content}" /> </td> </tr> </table> <input value="Submit" type="submit" name="command link parameters&Submitting+control=edit-item-submit&Fast+track+action=uploaditem.submit"/> <a href="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/page?save=false&id=%2Fgroup%2FContentTest%2FSome+Stuff%2F"><span >Cancel</span></a><br /> </form>
A couple of observations:
1. "name" and "desc" from the ViewParameters conflict with fields defined in this POST form. That's easy to fix, just change the names.
2. Duplicate input fields are being created for each of the POST form fields, one "fossilized". Why is that?
3. The submit button seems to be ited to uploaditem.submit, which is what we expect. So why isn't it called on submit?
Changing the field names might be a good first step. Chances are the ViewParamters will continue to capture the old values.
I think it might also be useful to conduct a more isolated example. Create a standalone app that just uploads a file into CHS using a form similar to the one defined for EditItem. That will allow me to experiment with file upload and POST operations. With that success in place, I can re-examine the workflow in Sousa Page tool and figure out how to upload new media files.
Created the start of a new tool in RSFExamples called ex5-post-form. I'll used this to test posting of simple information and file upload.
April 21, 2008
Changed the name of the example to rsf-ex-5. Compiled and ran it. Runs fine, but still uses a GET form.
Form changed to be POST:
<form method="POST" rsf:id="hello-form"> <span rsf:id="hello-instructions" style="font-weight: bold;" >Hello instructions goes here.</span><br/><br/> <span rsf:id="first-name-label">Name label here.</span> <input rsf:id="first-name" type="text" name="first" size="40"/><br/> <span rsf:id="last-name-label">Description label here.</span> <input rsf:id="last-name" type="text" name="last" size="40"/><br/><br/> <input rsf:id="hello-submit" type="submit"/> </form>
I'm not going to make any changes to the layout or fields in the form. This will better illustrate to to students how to compare GET with POST forms.
The receiving form bean is coded as:
class FormBean { public String first = null; public String last = null; public String submit() { System.out.println ("**** FormBean Submit."); return "second"; } }
It can't get much more simple than that!
The code for MainProducer.fillComponents() is:
UIForm newForm = UIForm.make(tofill, "hello-form"; UIMessage.make(tofill, "hello-instructions", "hello_instructions"); UIMessage.make(tofill, "first-name-label", "first_name_label"); UIInput.make(newForm, "first-name", "#{formbean.first}"); UIMessage.make (tofill, "last-name-label", "last_name_label"); UIInput.make(newForm, "last-name", "#{formbean.last}"); UICommand.make(newForm, "hello-submit", "Submit", "#{formbean.submit}");
Note that the ViewParameters parameter to UIForm.make() has been eliminated and a UICommand has been added to link the submit button to a method in the FormBean. The two text fields should now be injected into the first and last properties of FormBean.
I defined the form bean in requestContext:
<beans> <!-- Define the action handler bean. --> <bean id="formbean" class="org.sakaiproject.tool.simple.components.FormBean" /> </beans>
Updated the MainProducer and SecondProducer code. All that's needed is to add the NavigationCaseReporter in MainProducer to forward request display to SecondProducer. Coded as:
public List reportNavigationCases() { System.out.println ("***** MainProducer.resportNavigationCases"); List caseList = new ArrayList(); caseList.add(new NavigationCase("second", new SimpleViewParameters (SecondProducer.VIEW_ID))); return caseList; }
Couldn't acess the tools from Mercury. Looks like the application didn't start up correctly. That usually means that there is a Spring error somewhere, likely in my applicationContext file. Closing </bean> tag was mispelled. Several other problems corrected, all in the applicationContext. Now compiles and displays the first view.
A new error is appearing:
Error getting constructor for class org.sakaiproject.tool.simple.components.FormBean --> org.sakaiproject.tool.simple.components.FormBean.<init>() java.lang.NoSuchMethodException: org.sakaiproject.tool.simple.components.FormBean.<init>()
Ha! The FormBean class wasn't declared as public. It took a careful look to find that one.
Form comes up with out error now.
Oh boy! Now I get the same error as in Sousa Page tool:
Target exception of class java.lang.SecurityException Successive lines until stack trace show causes progressing to exception site: Error invoking action --> Writing to path formbean.first is not permissible - make sure to mark this p ath as request addressible - http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=R equestWriteableBean
Let's try adding settors.
No help, same error message. However, I did make a bit of a break through. That's a URL in the error message referring to the RSF Wiki! Doh!
If I read it right, I need to add my form bean to this to the list of request addressible beans in the applicationScope:
<bean parent="requestAddressibleParent"> <property name="value" value="hellobean,formbean"/> </bean>
Significant progress. Form now goes to SecondProducer. The FormBean.submit() method is being called. However, an instance of the form bean is not being injected into SecondProducer.
Antranig tells me that the bean is deallocated before the second producer is reached. This producer is actually a separate request cycle to ensure bookmarkability and back button works. He indicated that there was a way to capture some POST data and force it into a ViewParameters before the primary request cycle finishes. This could be passed off to the secondary view. While this work work for simple data (names, etc.), it won't work for files. That's probably ok.
April 22, 2008
Did a search on RSFWiki for Resulting View Bindings. It seems that this happens in the NavigationCase code. The navigation case code in Ex. 5 is:
public List reportNavigationCases() { System.out.println ("***** MainProducer.resportNavigationCases"); List caseList = new ArrayList(); caseList.add(new NavigationCase("second", new SimpleViewParameters (SecondProducer.VIEW_ID))); return caseList; }
Note the creation of SimpleViewParameters. This could be any ViewParameters object. If the handler bean is injected into the producer with the navigation case, it's data will be available before the end of the intial request, thus allow POST data to be communicated to the secondary view via GET parameters. This is very convoluted, but should work. Nowever, I do note that MainProducer.reportNavigationCases() is called before the request is processed. That might mean that the FormBean isn't initialized yet.
To make this work, I need to inject the FormBean into MainProducer.
See also Chat with Antranig April 22, 2008
April 24, 2008
Additional conversations with Antranig suggest one of two approches for handling POST forms (file upload): handle the request in the same producer as the form (the default), or use a navigation case to forward resulting display. If the later, data is going to have to be stored in session state.
The current content editing portion of EditItemProducer looks like this:
<tr> <td align="right"><span rsf:id="edit-label">Content:</span></td> <td colspan="2" align="left"> <input rsf:id="edit-input-text" type="text" name="content" size="60"/> <input rsf:id="edit-input-file" type="file" name="content" size="60"/> </td> </tr>
By moving this part into it's own form on the same page, uses will be able to uploade a file (or editing content) in place on the same page. Personally, I think that this is kinda confusing from a UX point of fiew, but RSF is really forcing me into this kind of approach. The alternatives are signficantly more complex.
This page needs to be split into three sections: General Parameters, Content, and Media Parameters. General parameters should always be displayed and editable. Content is displayed for new items or dropped down to change in the case of edit. Finally, Media Parameters are optionally displayed based on the media type. This could be done as three separate menus that are all processed by EditItemProducer and then have a separate link to move off to Preview and final save. The only problem with this approach is that I'd need to check for changes to fields that have not been saved if the preview link is selected. Although, the preview will have the option to return to edit, if something was missed.
Added caching of form data into user session in FormBean. Removed injection of FormBean into SecondProducer. Modified code in SecondProducer to take data out of user session and display it. Compiles and runs correctly. This is about the best and simplest example of how to use a POST for via RSF. I need to move this into the training materials.
Made a back up to RSFExamples-042408.
Next up is to expand this example to include file upload!
Cloned Ex5 into Ex6. Base example compiles and runs.
Changed MainProducer to show a file input.
Changed FormBean to get a file (by extracting code fomr UploadBean in the RSF example).
Stubbed SecondProducer to show a default string. Allows us to see if we reach that view.
Compiles and first view comes up. Selectinng a test text file generates the following error in the FormBean:
2008-04-24 12:01:25,734 INFO (PostDecoder.java:79) - <PostInit: key Submitting c ontrol value hello-submit> 2008-04-24 12:01:25,765 WARN (RSFActionHandler.java:213) - <Error invoking action> Target exception of class java.lang.IllegalArgumentException Successive lines until stack trace show causes progressing to exception site: Error invoking action --> Error setting dependency multipartMap of bean formbean --> class org.sakaiproject.tool.simple.components.FormBean has no writeable prop erty named multipartMap java.lang.IllegalArgumentException: class org.sakaiproject.tool.simple.component s.FormBean has no writeable property named multipartMap at uk.org.ponder.rsac.RSACBeanLocatorImpl.createBean(RSACBeanLocatorImpl
Sigh. I edited the FormBean in Example 5, rather than Example 6. Another problem that arises from copy/paste/cloning.
Copied changes to the correct file. Restored code in ex5/FormBean.
It's starting to work. Second view displayed. The following entries made in catalina.out by FormBean:
**** FormBean Submit. **** FormBean: request type is action **** FormBean:: Map {} **** FormBean: Reqmap: command link parameters&Submitting+control=hello-submit&Fast+track+action=formbean.submit : [Ljava.lang.String;@3c5d62 2008-04-24 12:09:52,703 INFO (SakaiRequestParser.java:109) - <Got tool dispatcher id of sakai.rsf.ex6 resourceBaseURL http://localhost:8080/rsf-ex-6/ baseURL http://localhost:8080/mercury/sakai.rsf.ex6/mercury/ and Sakai PID 6e40fbab-4da9-45a1-002a-dfc253ad3f82>
This makes it look like the map is empty.
Looks like I may have missed adding the apache commons upload resolver, etc. in Maven. Copied from RSFWiki.
Added new dependencies, no help.
Working carefully through the example, but still no help. Map has no entries.
April 28, 2008
Was reading through the RSF Q&A section on file upload and had a look at the Spring documentation on CommonsMultipartResolver. The encoding type is mentioned. Perhaps that is my problem. I can add an ENCTYPE of "multipart/form-data", which my HTML books says is required for file upload. Darn. It's already there. Well, I guess that's not the problem.
I packaged up the example and sent it off to Antranig. Maybe he can see my problem.
Response from Antranig:
AntranigBasman: Looks like you failed to follow this excellent guide
AntranigBasman: http://bugs.sakaiproject.org/confluence/display/BOOT/File+Uploads+with+RSF
AntranigBasman: Looks like the key in this case is to configure the Sakai request filter correctly
mjnsakai: I wasn't aware of this excellent guide.
mjnsakai: But I can certainly fix the request filter.
No wonder it didn't work. My request filter didn't allow it to work!
Changed the request filter setup in web.xml to the following:
<filter> <filter-name>sakai.request</filter-name> <filter-class>org.sakaiproject.util.RequestFilter</filter-class> <init-param> <param-name>upload.enabled</param-name> <param-value>false</param-value> </init-param> </filter>
Viola! It works with the following results:
**** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@1503061} **** FormBean: Iterate over keys: **** FormBean: Reqmap: command link parameters&Submitting+control=hello-submit&Fast+track+action=formbean.submit : [Ljava.lang.String;@19857ee **** FormBean: upload report is null.
Not sure why it didn't iterate over the keys, but at least I have a map entry with something in it!
The map entries have a key and a value of type MultipartFile.
See http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/web/multipart/MultipartFile.html
If the size of this file is zero, it means the user didn't upload a file and left the field empty.
While I'm getting something, I'm not sure what it is. I get the following error when I try to cast the map entry results into a MultipartFile:
**** FormBean: Iterate over multipart map keys: **** FormBean: Multipart Exception java.lang.ClassCastException: [Ljava.lang.String; at org.sakaiproject.tool.simple.components.FormBean.submit(FormBean.java:63)
Looking over Steve Githen's example, he doesn't override the MultipartResolver strategy. I think I'll comment that out and see what happens.
No help. Tried several different object types all resulting errors of the form:
2008-04-28 23:18:43,007 INFO (RenderUtil.java:137) - <Unpacked command link key Submitting control value hello-submit> 2008-04-28 23:18:43,023 INFO (RenderUtil.java:137) - <Unpacked command link key Fast track action value formbean.submit> 2008-04-28 23:18:43,038 INFO (PostDecoder.java:79) - <PostInit: key Fast track action value formbean.submit> 2008-04-28 23:18:43,054 INFO (PostDecoder.java:79) - <PostInit: key Submitting control value hello-submit> **** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@1903892} **** FormBean: Iterate over multipart map keys: **** FormBean: Multipart Exception java.lang.ClassCastException: [Ljava.lang.String; at org.sakaiproject.tool.simple.components.FormBean.submit(FormBean.java:65)
This is weird. "[Ljava.lang.String" doesn't seem like a valid object type. Further, the info seems to suggest that an object of "CommonsMultipartFile" is present.
I think I found the problem. I was iterating over the reqmap instead of multipartMap.
Ok, progress. Results are:
**** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@1fb6021} **** FormBean: Iterate over multipart map keys: **** FormBean: Value of fileupload is Key is [fileupload] with a sizeof [24] and a name of [fileupload] **** FormBean: upload report is null.
Code can be changed to getOriginalFileName() to get the name of this item. I can also get the input stream and print the actual file contents, or just pass it over to ContentHosting.
April 29, 2008
Changed the FormBean code example to show information about the file being uploaded:
**** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@16c5f1a} **** Formbean: size of file is: 24 **** Formbean: original file name is: test.txt **** FormBean: content type is: text/plain
Now I'm ready to save the contents in a state variable and show it on the SecondProducer page.
Saved the stream in the session state. There might be better ways to do this, but it seemed to work.
Coded SecondProducer to display the content.
Content is correctly displayed. Example full works at this point.
Backed up all examples. Folded these new examples (Ex5 and Ex6 into Sakai training.
Ready to use this information to get file upload working in Sousa now.
Modified web.xml to:
<!-- The Sakai Request Handler - modified to enable file upload. --> <filter> <filter-name>sakai.request</filter-name> <filter-class>org.sakaiproject.util.RequestFilter</filter-class> <init-param> <param-name>upload.enabled</param-name> <param-value>false</param-value> </init-param> </filter>
This seems a bit strange, since the parameter is set to false, but it works in the example so who am I to argue? Perhaps this disables the Sakai mechanism so that the RSF one can work.
Removed the multipartResolver from applicationContext. Not needed.
Changed Navigation Case Reporter to use SimpleViewParameters. Since everything needs to be in the user session, I don't need anything else.
Still getting RequestWriteableBean errors.
Checked the applicationContext definition carefully. It seems to be right.
The file field has an rsf:id. I'll try taking that out. it shouldn't be needed.
Ok, the error went away. I commented out the desc and id fields from template and the producer. The type, name, desc, and id fields are getting created as hidden fields, likely because the EditItemProducer implements ViewReporter. I might need slightly different names for the edit fields here, since they are included automatically and hidden. It might be worth trying to include properties in the UploadItemBean for these feilds and see if it fails again.
Changed the name of the editable fields to xname and xdesc in template and EditItemProducer.
Changed bindings in EditItemProducer to refer to #{uploaditem.xname} and #{uploaditem.xdesc}.
Added properties and setters in UploadItemBean.
This worked. Yes! Now I need to move on to extracting information into session state and forwarding it to the PreviewProducer.
Dealing with an uploaded file means putting it into a temporary resource somewhere. Ideally, this should be a hidden collection managed by it's own service. Just to test out the file upload, I'm going to punt on creating resources for the moment. I'll use EditItem.setContent() to set the original file name as the stubbed content.
Submit recoded as:
public String submit() { // Get the edit item and it's state values. Session session = SessionManager.getCurrentSession(); EditItem item = (EditItem) session.getAttribute (EditItemProducer.EDIT_ITEM); // Update changes to name and description. item.setName (this.xname); item.setDescription (this.xdesc); // Add the new file content to the edit item. CommonsMultipartFile mf = (CommonsMultipartFile)this.multipartMap.get("content"); String fn = mf.getOriginalFilename(); item.setEditContent (fn); // mf.getInputStream()); // I'll need this later to create the ContentResource. System.out.println("**** Sousa Upload Bean new name:"+this.xname); System.out.println("**** Sousa Upload Bean new description:"+this.xdesc); System.out.println("**** Sousa Upload Bean new file:"+fn); return "preview"; }
I should put a check into this code to see if the user didn't specify a file. It really screws things up if they don't, so I need to handle this error case. I could re-direct back to EditItemProducer, perhaps with some kind of error code in EditItem.
Results from above are:
**** Sousa Upload Bean new name:null **** Sousa Upload Bean new description:null **** Sousa Upload Bean new file:Sakaiger.AVI
Added a field count on multipartMap:
**** Sousa Upload Bean - field count: 1 **** Sousa Upload Bean - new name: null **** Sousa Upload Bean - new description: null **** Sousa Upload Bean - new file:Sakaiger.AVI
I'm seeing fossilized fields in my rendered EditItemProducer view. The names of the input field are being changed to the rsf:id and my names are shifted into hidden fields:
<tr > <td align="right"><span >Name:</span></td> <td colspan="2" align="left"> <input value="Sakaiger" type="text" size="60" name="edit-item-name"/> <input type="hidden" name="edit-item-name-fossil" value="istring#{uploaditem.xname}Sakaiger" /> </td> </tr> <tr > <td align="right"><span >Description:</span></td> <td colspan="2" align="left"> <input value="Megan with sakaiger" type="text" size="60" name="edit-item-desc"/> <input type="hidden" name="edit-item-desc-fossil" value="istring#{uploaditem.xdesc}Megan with sakaiger" /> </td> </tr>
May 3, 2008 (on the way to Moscow)
Fired up my Post form example (ex5) to have a look at the rendered HTML. It looks like this:
<form action="http://localhost:8080/mercury/sakai.rsf.ex5/mercury/main" method="post"> <span style="font-weight: bold;">Please enter your first and last name.</span><br /><br /> <span >First Name:</span> <input value="" type="text" size="40" name="first-name"/> <input type="hidden" name="first-name-fossil" value="istring#{formbean.first}" /> <br /> <span >Last Name:</span> <input value="" type="text" size="40" name="last-name"/> <input type="hidden" name="last-name-fossil" value="istring#{formbean.last}" /> <br /><br /> <input value="Submit" type="submit" name="command link parameters&Submitting+control=hello-submit&Fast+track+action=formbean.submit"/> </form>
Now lets have a look at Sousa Page:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/edititem" enctype="multipart/form-data" method="post"><input type="hidden" name="op" value="new" /> <input type="hidden" name="type" value="video" /> <input type="hidden" name="name" value="Sakaiger" /> <input type="hidden" name="desc" value="Megan with sakaiger" /> <input type="hidden" name="id" value="/group/ContentTest/Some Stuff/" /> <table border="0" cellpadding="2"> <tr > <td align="right"><span >Name:</span></td> <td colspan="2" align="left"> <input value="Sakaiger" type="text" size="60" name="edit-item-name"/> <input type="hidden" name="edit-item-name-fossil" value="istring#{uploaditem.xname}Sakaiger" /> </td> </tr> <tr > <td align="right"><span >Description:</span></td> <td colspan="2" align="left"> <input value="Megan with sakaiger" type="text" size="60" name="edit-item-desc"/> <input type="hidden" name="edit-item-desc-fossil" value="istring#{uploaditem.xdesc}Megan with sakaiger" /> </td> </tr> <tr > <td align="right"><span >Select a video file to upload:</span></td> <td colspan="2" align="left"> <!--<input rsf:id="edit-input-text" type="text" name="content" size="60"/>--> <input size="60" name="content" type="file" id="edit-input-file"/> </td> </tr>
I don't have agreement between the input field names and the backing bean property names. Gonna try putting name attributes in the template for xname and xdesc.
That didn't change anything. The name was overridden with the rsf:id name. I think that's was going on here. It doesn't matter what I call it. What matters is the rsf:id tag name, and the names of the bean properties. So why do the come up as null in the bean?
I think I have found a bug. If I edit the xname and xdesc fields, they appear in the bean. If I leave them unchanged, they appear as null. This CAN'T be the correct behavior. The value should be injected into the bean from the form, even if no change occurs.
Now I have a design decision to make. I could merge the new item and edit item views together. Ah, a better idea. These values are already captured into the EditItem object being saved in the session state. I can update the values if they change, and leave them alone if unchanged. That should work.
This also implies that the whole line of inquiry on field names was a red herring. I don't need to call them xname and xdesc, though there is also the hidden fields of the same names. Shouldn't matter because RSF is overriding the names anyways.
Verified theorized behavior:
**** Sousa Upload Bean - field count: 1 **** Sousa Upload Bean - new name: Cute Sakaiger **** Sousa Upload Bean - new description: Megan with cute sakaiger **** Sousa Upload Bean - new file:Sakaiger.AVI
The name and desc fields were edited on the Edit Item view form. Both come through into the command bean. Also put in a display of the video file name into PreviewProducer which was correctly display. This is all good news since I don't have any blockers to move forward (after nearly a month and a half of frustration).
To the get preview working, I need to create a hidden resource and refer to it. Some kind of temp resource service is needed. Other people have used similar techniques, but there is nothing in the mainline to support it.
It's been so long struggling with file upload that I've completely lost my train of thought with respect to parameter editing. I think video has three parameters: height, width, and autostart. Added code for video parameters:
**** Sousa Upload Bean - field count: 1 **** Sousa Upload Bean - new name: Cute Sakaiger **** Sousa Upload Bean - new description: Megan with fierce sakaiger **** Sousa Upload Bean - new file:Sakaiger.AVI **** Sousa Upload Bean - parameter 0: 100 **** Sousa Upload Bean - parameter 1: 100 **** Sousa Upload Bean - parameter 2: true **** Sousa Upload Bean - parameter 3: null
Parameters are coming through ok. At this point, EditItemProducer is fully working. Now I need to get the PreviewProducer view working. After that comes save and one pass through the workflow will be operational. I need to go back and implement cut and paste content as an alternative to file upload.
May 4, 2008 (in Moscow)
Based on the code in EditItem, it looks like I have to create a ContentResource and then set the id for the EditItem. The design seems a bit muddled to me, thought it may be that I've forgotten how to use it (sad, since I wrote it). EditItem has a save() method, but it is unimplemented at this time. This will be the key piece of code that makes editing work, in some ways.
There is a question on where to put the code that creates a new ContentResource. If I put it in UploadItemBean, what happens if there is an error? One thing that could be done is to create an error page that would provide an error code and then send the user back to an appropriate point in the edit workflow.
Created EditErrorProducer and editerr.html. An error code (bundle key) is saved in the user session and picked up the EditErrorProducer view to display an error that can be localized. Added SVN tree.
Verified that transfer to EditErrorProducer view will occur if "editerr" is returned out of UploadItemBean.
May 5, 2008 (in Moscow)
Creating the temporary content resource must be handled carefully. I plan to create the resource with a GUID, with its real name, type, content, etc. At save time, this can be blasted on top of the old resource or re-id'ed into a new resource. No, that' won't work.
In the process of coding resource creation in UploadItemBean, I've decided that this really should be folded into the SequencerService. Anything that works directly with the ConentHostingService should be down below the SequencerService layer. By creating the resource directly in UploadItemBean, I'm violating separation of concerns.
Given an EditItem, the following operations will likely be needed:
- create a temporary resource
- update a temporary resource
- save the temporary resource into it's permanant form
Create can probably be folded into update, since it's a special case. Since save() already exists (though not implemented), this means that I'm adding one new method to EditItem: updateTemp(). That's not too bad.
I should read my own code more often. There is a saveProperty() method in EditItem that does most of what I need. What's really needed is a saveContent() method to update the content in the item. I'm creating this in two forms:
public void saveContent (InputStream stream); public void saveContent (bytes[] text);
This handles both cases (though there may be more in the future for special kinnds of editing, TBD).
Later that evening...
Implemented saveContent() for both stream and text. Changed internals of EditItemImpl around a bit so that I could easily get a resource and editResource creating if needed. This stuff should all be tested (naturally), as I've tinkered with the way EditItem works.
May 6, 2008 (in Moscow)
'Added call to ContentHanlder.saveParameters(). This should save parameters to the temporary content resource instance.
Uncommented display of content in PreviewProducer. In theory (heh), all the code needed to create a new video item is in place at this time.
Error:
Error invoking action --> Error invoking method submit in bean at path uploaditem.submit java.lang.NullPointerException at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:2726) at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:3046) at org.sakaiproject.content.cover.ContentHostingService.addResource(ContentHostingService.java:328) at org.sakaiproject.sousa.impl.EditItemImpl.createResource(EditItemImpl.java:374) at org.sakaiproject.sousa.impl.EditItemImpl.getResource(EditItemImpl.java:354) at org.sakaiproject.sousa.impl.EditItemImpl.saveParameter(EditItemImpl.java:280) at org.sakaiproject.sousa.util.CEVideo.saveParameters(CEVideo.java:142) at org.sakaiproject.sousa.util.ContentElementHandler.saveParameters(ContentElementHandler.java:194)
CHS.addResource() didn't like me passing it a null pointer for the content. Stubbed content to an empty byte array.
Collection id was null. Set it in the EditItem in EditItemProducer.
****** UploadItemBean: item name: Sakaiger ****** UploadItemBean: item coll id: null ****** UploadItemBean: item type: video
There is a problem with the way item types are stored. Currently, I'm saving image as "image", when it should be "image/gif". I need some way to map file endings to content types. CHS does this somewhere.
Well, that did the trick. Some solid progress. The preview is showing, but not the video image. Here is the rendered HTML:
<!-- Content elements for preview. --> <div id="element"> <div style="text-indent: 1em;">Sakaiger.AVI</div> <embed width="200" height="200" src="http://localhost:8080/access/content/group/ContentTest/Some Stuff/Sakaiger"/> </div>
The name of the item is correct (Sakaiger). The collection id looks right. No type is specified, which might cause a problem. The plug-in missing view is shown.
May 7, 2008 (still in Moscow)
Though more work is needed to get video types to work, I think I;m going to shift to using an image as a test case. In part, because the image attributes of height and width were working previously. It will allow me to test to see if they are still working when a new item is created.
Well, here's an interesting problem, the Writeable Bean security error is back. This is very strange since it works just fine for video, but now fails when I try to add an image.
More strangeness. The isEditable flag in CEImage is false. I shouldn't have been able to edit the image.
That is explained by the fact that the file field in the form doesn't have an rsf:id tag. It's always present.
I'm going to try to create the control via a UIInput call, rather than hard-wiring it into the template. This should work, but lord knows I have struggled with RSF POST forms.
Ok, adding the rsf:id tag caused the file upload field to disappear, now I'll add it back by adding the UIInput and changing the editable flag to true for images.
That worked. File upload field is now visible.
Found problem with WriteableBean, too. UIInput refers to "po" instead of "#{uploaditem.p0}". Need to use an RSF-EL to tie the field to the action handler bean. Nope. That theory was wrong. Problem still there. Ok, finally solved. I had to eliminate reference to the file upload field name, which was "content". Not just in the template, but in the UIInput call as well. Name field called as null.
However, image is not displayed in the preview. There is something wrong with the temp content or access to it. So the last two hours of work bring me up where I was with video, but now images are broken as well.
May 8, 2008 (Flight Moscow to Boston)
Fired up Sakai to have a look at what was created as a content resource in the file upload process. There is an entry in the Moscow collection, but it has no name, and a type of "image". It has a size of one byte, which is suspicious since the content was supposed to have been added to the resource after it was created.
Maybe not so baffling after all. It doens't look like I saved the content into the resource. I had originally stubbed this to put the file name into the EditItem, but it doesn't look like the content was ever updated to it.
There is also the matter of file extensions to MIME type mapping. I had a look through the content hosting service, especially the type registry, but I didn't see anything that supported mapping. I do recall this being present in Sakai somewhere, perhaps as part of the configuration variables. A search of Sakai files for "mime" reveals a mime type file managed by Samigo, and couple of classes in OSP. Checked sakai.properties - nothing there. The Resources tool handles this problem, but it didn't turn up in the search.
As it happens, there is already the start of a media type table in ContentElementHandler. Perhaps the best thing to do would be to re-design this table to handle extension to mime type mapping as well as being able to get the content handler from type. It's a bit tricky. This table supports the notion that certain types can be handled together, like image/jpeg and image/gif.
Rather than screwing up what's there, I've created a new list in ConentElementHandler to translate extensions into types. Eventually these two approaches should be merged. In a moment of supreme irony, I created an inner class after stated just yesterday that inner classes are NEVER needed. In this case, the inner class is a simple data structure consisting of a MIME string, file extension string, type name, and handler.
Created ContentElementHandler.getType () which takes a file extension and returns the registered MIME type. Had to change the API of saveContent() to take an optional newType. There is no setType() method currently. Content type is always gotten from the ContentResource. Since we really only know the final type when we are saving the content to a temp resource, it's logical to pass it in here.
Well, the good news is no exceptions. The bad new is no image, either. My trace msgs indicate no file was uploaded, though I did select one. The generated HTML in preview looks good:
<div id="element"> <div style="text-indent: 1em;"/> <img width="50%" height="50%" src="http://localhost:8080/access/content/group/ContentTest/Moscow/Canon"/> </div>
Note that even the image paramters are correctly applied.
No content resource was added to the Moscow collection, either.
File upload got broken somehow. It's not finding the "content" field name.
Thinking about this problem (while standing in line to board the airplane), I recalled deleting the name attribute on the file input field of the
form thinking that I didn't really need. Tried adding it back, but it didn't work.
It looks like the field name is now "edit-input-file". I'll try putting that into UploadItemBean and see if we can get this sucka to work.
SUCCESS!
Finally, after weeks of effort, it works. The temp content resource was corectly created, and displayed in the preview page with parameters in place.
I had to access the MultipartMap using the field name created by RSF based on the rsf:id tag I gave to the file input field.
The next logical step is to work on save. The temp resource shows up in the target collection, but it has no name. It might be best to give it some kind of temp name, just in case manual clean up is needed. This is just a matter of adding the Display Name property. May as well add description, too. Tested and works.
From the preview page, three actions are possible: re-edit the new item, cancel the whole thing, and commit the new item.
Re-edit means returning to EditItemProducer view.
Cancel means advancing to EditPageProducer view, deleted the temporary ContentResource, and deleting the EditItem object in the user session.
Save means advaning to EditPageProducer view, updating all data in the ContentResource, and deleting the EditItem object.
May 24, 2008 (Return to Boston from Athens, GA)
Looking at the code, it seems like save is already in place. What's missing is the cancel edit operation. Cancel should check for a temporary resource and delete it.
Yes, it seems that a new media item (image in this case) is being created correctly with attributes, but it has a (temp) name. It might be best to just not name it as temp and only handle the cancel action. Once created, the item can't be edited - throws exception.
Removed the "(temp) prefix on temporary resource items. Looks like cached EditItem object is cleared already.
Editing of any media object is broken. Editing a sousa page seems to be still working.
Here is the error when trying to edit a media item:
**** EditItemImpl: create resource name: null **** EditItemImpl: create resource coll id: null **** EditItemImpl: create resource type: null 2008-05-24 15:17:10,609 WARN (RenderHandlerBracketer.java:110) - <Exception rendering view: > java.lang.NullPointerException at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:2726) at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:3046) at org.sakaiproject.content.cover.ContentHostingService.addResource(ContentHostingService.java:328) at org.sakaiproject.sousa.impl.EditItemImpl.createResource(EditItemImpl.java:389) at org.sakaiproject.sousa.impl.EditItemImpl.getResource(EditItemImpl.java:360) at org.sakaiproject.sousa.impl.ItemImpl.getType(ItemImpl.java:116) at org.sakaiproject.sousa.tool.EditItemProducer.fillComponents(EditItemProducer.java:148)
There are two versions of getResource(): one in EditItem and one in Item. When editing an existing item, we need to call the super version in Item. Corrected code in EditItemImpl. It no longer crashes, but changes to the attributes are not saved, perhaps because it thinks that the resource has already been created.
Some clues:
**** PageObjectProducer: saving parameters. **** EditItemImpl: create resource name: null **** EditItemImpl: create resource coll id: null **** EditItemImpl: create resource type: null ***** EditItemImpl: Error when updating the resource: null **** EditItemImpl: create resource name: null **** EditItemImpl: create resource coll id: null **** EditItemImpl: create resource type: null ***** EditItemImpl: Error when updating the resource: null
Note that saveParameters() is getting called in Page Object Producer, but we get an error when the resource is updated. We shouldn't be creating a resource in saveParameters().
Looks like a similar kind of problem. EditItem.getResource() is called when Item.getResource() should be called. Added a check in EditItem.saveParameters() to call the appropriate one.
Now I'm getting a permissions violation, which is kinda weird considing I created all of these objects:
**** PageObjectProducer: saving parameters. ***** EditItemImpl.getEditResource: Permission violation on accesing resource item in sequence. **** EditItemImpl: Error when updating the resource in saveParameters(): null ***** EditItemImpl.getEditResource: Permission violation on accesing resource item in sequence. **** EditItemImpl: Error when updating the resource in saveParameters(): null
Added a debug line. Need to re-test.
When creating a new media item, the system prompts for name, desciption, and type. While type is necessary, it can be hard to remember what to name your resource until you select it in the next screen. It might be better to drop name and description from the NewItemProducer page, especially since it's present on the EditItemProducer anyways.
Cancel from edit item needs to be carefully handled. There are two cases:
- Cancel the creation of a new media item by deleting the temp content resource.
- Cancel the edit of an existing media object by not updating any changes to attributes.
To Be Done
- Remove temp label on new media items. – done.
- Delete resources and cached media item on cancel.
- Fix edit of attributes on a new media item. - no longer crashes, but does't update changes to attributes.
May 26, 2008 (Home Again!)
Made a change to getEditResource(), since it seemed to be getting an editId of null. This is where the security violations seemed to be arising from. They are gone, but can't edit and save now.
May 31, 2008
If parameters such as height and width are null, they are rendered as height="null". This cases the image (in this case) to be invisible. Added to code to check for null parameters. Still not displaying. Problem is deeper. The media type in CHS is "image" instead of "image/jpeg", which will cause a problem.
Oh, this code is truly screwed up. Creating a new media item creates FOUR! ContentResources, each with different ids. This is all tied in with tempId, which I'm beginning to suspect was a bad design approach. The original intent to was to create a temporary ContentResource (hence the tempId), and then delete it if not updated. However, I've drifted over to just creating the resources and deleting it later if canceled (though there may be problems with this approach, too).
Made EditItem.createResource() a public method. Called from upload bean now. getEditResource() no longer creates the resource if it doesn't exist.
Ok, we're getting close. Preview is working again. Multiple resources are no longer being created. However, I got a null pointer exception when I tried to re-edit the media item - a null pointer trying to create a resource. I think this is from having an empty file input.
Additional adjustments were needed in upload bean to handle the case where file is not being re-loaded on a re-edit. Image media types now seem to work completely. Likely more testing is needed. Cleaned up code.
To Be Done
- Delete resources and cached media item on cancel.
- Finish other media objects and their parameters.
- Test everything!
Jun. 2, 2008
Fixed a small problem in CEVideo.editContent() that prevents video items from being created. Tested and works, though player controls are not displayed.
Started working on Plain Text editing. Enabled the content field in the POST form. After some tinkering in CEPlainText, I got the upload bean to receive it and save it off to the EditItem. Displays correctly as a preview. Now I need to save it off to a ContentResource. Added code to UploadItemBean to create and save plain text content. Plain text support now working.
Fixed video - now works.
Added code for URL - now works.
Parameters are not added to display of video, audio, or URL content at this time.
Added code for Audio - works on WAV files. Had to modify the EXT to MIME tables from "audio/x-wave" to "audio/wav". Now works.
Display parameters added for the following media types:
- Video: height, width, autostart
- Audio: autostart
- URL: height, width
- Image: height, width
Editing is fully implemented for these and plain text.
March 1, 2008
It is time to return to the Sequencer tool and bring it up to the level coding in the Page tool. After that, a release is in order, though I might sneak in a few more media types.
One of the things I want to change about the Sequencer tool is the reliance on a fixed directory to hold sequences. They should be able to live anywhere and now that I've determined that I create my own media types in the CHS, there's no need to restrict them to a special place. Mostly, this means changing MainProducer, which I am thinking of replacing with SequenceProducer – the name seems a bit more expressive than "Main".
Added sousa.util dependency to Sequencer Maven project. This will bring in the shared UI code.
Removed unused producers and view parameters including:
- EditPageProducer
- EditPageViewParameters
- EditTileProducer
- EditTileViewParameters
- NewPageProducer
- NewPageViewParameters
Created a sequence icon (sequence.gif) and added it to sousa-seq-tool.
For some reason (could it be a bug?) the new sequence icon is not showing in the MainProducer view. What ever the problem, I don't think it worked before, either. I restored the original URL and it still doesn't work. The problem was with the template. A wrapping tag was used for the link, which overrode the img tag (a link) inside of it. My moving the image outside, got it to work.
Created SequenceProducer and SequenceParameters to replace MainProducer and MainViewParameters. This is the first step towards making sequences live anywhere.
SequenceProducer has a view id of "sequence", which means that a new template must be created (based on the page template). Complies ok, but by moving the DefaultView from MainProducer to SequenceProducer, I'm sure is VERY broken.
Created a sequence.html template by copying main.
Added SequenceProducer.java, SequenceParameters.java, and sequence.html to SVN.
Started converting over to EditEvent action constants in SequenceProducer.
Started the process of merging code cover from PageObjectProducer to SequenceProducer. Copied page.html content into sequence.html.
The bulk of the logic in fillResources() is commented out due to all the links off to other views.
Things are compiling without error. Fired Sakai up and checked the sequence tool. It comes up with out error. No real content since I stubbed out fillResources(). But by carefully adding that code back in, I should get the sequencer select to work again.
Next Steps
- Add custom sequence icons to home select page. - done
- Remove unused views in Sequence tool. - done
- Allow sequences to be created anywhere. - in progress
- Use EditEvent action constants in sequence code.
- Create sequences using media type of "sousa/linear-seq"
- Update the Sequence tool to use the EditChainService.
- Update the Sequence tool to use content handlers, etc.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Enable CHS to launch a page into the page viewer.
- Add CHS action to edit a page view (layout).
- Look into enabling Entity Broker
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 2, 2008
Enabled the logic in SequenceProducer.fillResources(), but commented out links to playing the sequence, adding new sequence, and delete sequence.
Compiled, works but no resources are displayed. Can drill down into folders. The first thing to get working is play sequence.
Added the link to the player. Temporarily changed definition of sequence to be "text/xml" so that I can test it.
Something strange. I changed isViewable() to isSequence() in the resource display block, but when I ran the code, the collections below the root disappeared.
Found the problem. I changed the template rsf:id to play-link while the collections were expecting add-link. Changed all to item link.
Can now link to player. Fixed return in PlaySequenceProducer. Also changed over to EditEvent constants.
Next Steps
- Allow sequences to be created anywhere. - in progress
- Create SequenceProducer and SequenceParameters - done
- Show folders and drill down - done
- Play sequence and return to SequenceProducer. - done
- Create new sequence and return to SequenceProducer.
- Edit sequence and return to SequenceProducer.
- Delete sequence.
- Use EditEvent action constants in sequence code.
- Create sequences using media type of "sousa/linear-seq"
- Update the Sequence tool to use the EditChainService.
- Update the Sequence tool to use content handlers, etc.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 3, 2008
Call away to road side emergency very late last night (no injuries, but annoying). While waiting for tow truck, I gave some thought Sousa design issues. These are reflected in Sousa Design and Sousa Learning Design and reflect thoughts on templating, branching sequences, and editing parameters.
Today, I'm working on getting the edit sequence and delete sequence links to work. Pretty much eliminated edit action events in view parameter files.
Confirmed that delete is working. Confirmed that editing is working.
That only leaves create new sequence. This may take some code changes, since the idea is to be able to create a sequence in any collection.
Link out to new sequence works. Able to edit, but update doesn't create new sequence.
Next Steps
- Allow sequences to be created anywhere. - in progress
- Create SequenceProducer and SequenceParameters - done
- Show folders and drill down - done
- Play sequence and return to SequenceProducer. - done
- Create new sequence and return to SequenceProducer.
- Edit sequence and return to SequenceProducer.
- Delete sequence. - done
- Use EditEvent action constants in sequence code. - done
- Create sequences using media type of "sousa/linear-seq"
- Update the Sequence tool to use the EditChainService.
- Update the Sequence tool to use content handlers, etc.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 4, 2008
Started work on creating sequences in any collection. Added link to folders. Created NewSeqParameters to pass collection id. Added code to NewSeqProducer to pass collection id through to EditSeqProducer. Added a collection id to the Sequence object. Created a new constructor to take name, desc, collId. Modified SequencerService.createSequence to take name, desc, collId. Modified creation of the Sequence object to take collection id.
All of the code is in place at this point. I'm trying to decide to tackle the EditChain update as well before testing. I should do this one thing at a time, but the creation and saving of sequence is kinda screwed up. I'm going to test that editing is ok, then update to the new EditChain mechanism. Once edit is ok, I can come back and fixe save/creation.
Added code to EditSeqProducer to cache the sequence and create an edit chain using the EditChainService. On edits, fetch sequence, make a copy, and apply edits from edit chain. Compilied code and ran it. Edit seems to still work ok. However, I get an exception when I try to create a new sequence. A simple problem with the wrong view parameter object being used to access the collection id. Fixed. Editing now works on a new sequence as well. All that's left is to get the save operation working for both existing and new sequences.
Collection id is not getting passed through to the EditSeqProducer from NewSeqProducer. This causes sequence.save() to crash at update time. I had created a hidden field in the New Sequence form. RSF handles this, so there is no need for me to do it explicitly. Didn't fix the problem. It turned out to be uninitialized in the sequence constructor.
Sequence was constructed, presumably with new type. However, it doesn't show up in the collection where it was created. It does show in the Resources tool, however. This is likely a media type / display problem. It's close to working. Editing existing sequences works. Changes are saved.
See some problems with cached sequence. When I try to edit a sequence, I'm seeing the previously created sequence. This happens in both new and existing sequences.
It's not the cached sequence that's the problem, it's the edit chain. It's not getting deleted after the previous editing.
Looks like the problem was using the wrong chain id to delete the edit chains on save. Yep. That fixed it. Edit full works now.
Changed isSequence() to test on "sousa/linear-seq". Sequences are now appearing in the collections they were created in. Sequences in "Content Sequences" are no longer visible (and should be deleted). This whole directory is no longer needed.
checked code into SVN.
Most of the major work in the Sequence tool is done now. The only remaining bit is to convert code to use content handers.
Added content handlers to EditSeqProducer, AddItemProducer, and PlayProducer. Added grid.gif and no_thumb.gif. Modified templates to agree with conventions.
Tested all - all work.
Next Steps
- Allow sequences to be created anywhere. - done
- Create new sequence and return to SequenceProducer. - done
- Create in any collection. - done
- Edit sequence and return to SequenceProducer. - done
- Create sequences using media type of "sousa/linear-seq" - done
- Update the Sequence tool to use the EditChainService. - done
- Update the Sequence tool to use content handlers, etc. - done
- Sequence edit page - done
- Add item page = done
- Sequence player page - done
- Remove deprecated methods in SequencerService, including support for EditChains there.
- Filter unsupported items for selection in AddItemProducer (both sequence and page). XML files and sequences should be filter, at least.
- Video media type.
- Audio media type.
- HTML link media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 5, 2008
Lot's of progress yesterday.
Added code to filter selections by adding ContentElementHandler.isSupported(), which checks to see if the content type of an element is currently handled. Added this test to both version of AddItemProducer (page and sequence tools). Works.
Started code clean up. Deleted MainProducer and MainViewParameters, which broke several references all needing to be fixed.
Deleted main.html, newpage.html, page.html, and addpage.html. These templates are not needed.
Removed Edit chain code from SequencerService. Methods included createEditChain(), getEditChain(), and clearEditChain().
Removed MainProducer bean definition from requestContext.xml.
Tested both tools. Both seem to work fine.
Had a quick look canceling out of add item in the page tool. Code and template is there. Must be something minor wrong with it. The Page tool has a cancel link that works. The problem is in the Sequence tool. While you can cancel out, the event isn't handled in EditSeqProducer. It tries to do an edit and gets a null pointer error. I also had to add an EditViewParameter object with a Cancel operation in AddItemProducer on the cancel link. Works now.
Check into SVN. Revision 46340. Made backup.
I'd like to document the process of adding a new media type to Sousa. The Resource tool supports a URL object that might be a good candidate. I need to figure out what media type it is, though. The following line in AddItemProducer (in the Page tool) can be enabled to see all media types going by:
System.out.println ("***** AddItemProducer - item ["+ name + "] has media type of ["+ type + "]");
This is a useful tool when trying to figure out media types. The above returns:
***** AddItemProducer - item [Nolaria.com] has media type of [text/url]
Thus we learn that the item "Nolaria.com" has a media type of "text/url".
Documentation is being put into [ Adding New Content Elements].
A CEUrl class was created to handle this new content element.
Coded and compiles, but not tested yet.
All told, it probably took about 30 minutes to add the type, though this took much longer because I was documenting the process as I went.
The URL element doesn't quite work fully. It shows up for selection. The thumbnail shows in EditTileProducer after being selected. When I update the tile, the framed URL is shown in EditPageProducer. However, the "Update" and "Cancel" links at the bottom of the page are missing. I figured this might be a template problem, but it doesn't seem to be working.
Next Steps
- Filter unsupported items for selection in AddItemProducer (both sequence and page). XML files and sequences should be filter, at least. - done
- Remove deprecated methods in SequencerService, including support for EditChains there. - done
- Cancel out of AddItemProducer in Sequence tool. - done
- HTML link media type.
- Video media type.
- Audio media type.
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 6, 2008
It occurred to me last night that I could fix CEUrl by using UIVerbatim until RSF is fixed.
Made some notes about video and audio thumbnails in Content Notes.
Modified the HTML rendering to use the following code until RSF is fixed:
// The following hack is being used due to a problem with RSF and Firefox. RSF converts an IFRAME with closing // tag into an empty block. Firefox requires IFRAME to have a separate closing tag. String content = "<iframe height=\"600\" width=\"600\" src=\""+url+"\">This browser does not support iFrames.</iframe>"; UIVerbatim.make(tofill, id, content);
Spoke to Antranig briefly about this problem. He says it cannot happen, so he will have to write a small test case and see if it fails for him and why.
Meanwhile, the above hack seems to work just fine. Pages containing a framed website can be created.
Started working towards support for video and audio. Found an AVI clip of Megan with the Sakaiger in Amsterdam. Uploaded it, but I don't think the Resource tool recognizes it as video. It shows a generic icon. Editing the details shows it to be of type " video/avi", however. That should suffice for my purposes.
I'm going to hunt around for more clips and examples. Different kinds of video formats would be good to test. Found three different kinds of video files: AVI, MPG, and WMV. Created CEVideo and CEAudio handlers. Registered, but stubbed out content developed with a text message. Thumbnails will show descriptions, eventually.
Added the embeded tag to view.html, play.html, and editpage.html. Added code to generate the embedded controller for audio and video. The AVI and MPG video both play. The WMV shows controls, but doesn't play, even when you hit the button. Some kind of bug there.
Checked code in. Revision 46409.
Next Steps
- HTML link media type. - done
- Video media type. - done
- Audio media type. - done
- Bug: should be able to select the new content elements from top level of Page tool for viewing - without being in a page object. - done
- Virtual lab media type.
- Property editors.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 7, 2008
Start work on content and parameter editing. Two new views will be required: NewItemProducer and EditItemProducer. I though I might have to have choice view to choose between creating an item and a page, but I think I'll just add two links in PageObjectProducer.
Created newitem.html for the new item view. It will have the same fields as new page, but also have a menu to select what kind of item to create.
Created NewItemParameters.java.
Created NewItemProducer.java.
Need to add these to SVN tree.
Next Steps
- Editing properties and content.
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 10, 2008
Added new files to SVN.
Created EditItemProducer.java, EditItemParameters.java, and edititem.html.
Added them to SVN.
Added link to PageObjectProducer to NewItemProducer.
Added form link from NewItemProducer to EditItemProducer.
Added to SVN.
Edited NewItemProducer to contain a dummy selection menu. This needs to be generated from ContentElementHandler somehow.
Stubbed out the EditItemproducer page with some text.
Modified EditItemParameters to include id, op, and type. Type is only used if a new item is being created.
Next Steps
- Editing properties and content. - in progress
- Add NewItemProducer - done
- Link to NewItemProducer from PageObject. = done
- Add EditItemProducer - done
- Add EditItemParameters - done
- Link from NewItemProducer to EditItemProducer - done
- isEditedable() methods on content element handlers.
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- getName() on handlers
- getType() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 11, 2008
Currently the design of editing provides two entry points: editing an existing content item and creating one in a directory. The first goes directly to EditItemProducer, while the second goes to NewItemProducer and then to EditItemProducer. The question is where are the edits saved? My first thought was that they'd be saved in PageObjectProducer, since that's where the user needs to return to, once an item is created or edited. However, this greatly complicates the PageObjectParameters. Last night the idea of a preview page occurred to me. Kicking on a save link in EditItemProducer would take the user to a PreviewProducer where the completed item would be shown. From their, the user can press "save" and go to PageObjectProducer, "edit" and go back to EditItemProducer, or "cancel" and go to PageObjectProducer with no save.
There are some advantages to this approach. First off, the user can see what affect changes to parameters will have on the displayed item. Sizing of images, for example. Secondly, the parameters can be bundled up along with a reference id and media type WITHOUT actually creating the content resource. Nothing to clean up if the user cancel's out (or navigates away from the page). This bundle would be saved to the session state and neatly picked up by the PageObjectProducer for final resolution.
Continued work on ContenElementHandler methods getTypes() and getNames(). These will be used to build the selection menu in NewItemProducer.
Next Steps
- Editing properties and content. - in progress
- isEditedable() methods on content element handlers.
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- getName() on handlers
- getType() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 12, 2008
Added getHandlers() to ContentElementHandler.
Added isEditable() to ContentElement, CEBase, and all handler classes.
Added code to build option and value arrays in NewItemProducer based on the isEditable() flag.
Originally I coded the NewItemProducer to create an array of options and values based on isEditable(), but I decided that this isn't necessary. Instead, the type selection should include all supported content elements, since any can be created. Later, in EditItemProducer, the content and parameter forms will be optionally included based on whether they are supported or not.
isEditable() may not be needed and probably should be backed out of all classes. Instead, I will need a isContentEditable() and isParametersEditable() booleans.
Well, the menu works, but unfortunately it includes the page object handler, too. I may need to provide some sort of list(s) filtered by atomic items, or items that can be simply edited. Heck, I may need to abandon this approach completely if I end up with a lot of custom editors.
Next Steps
- Editing properties and content. - in progress
- isEditedable() methods on content element handlers. - done
- getName() on handlers - done
- getType() on handlers - done
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 13, 2008
It seems likely to me that there will be more than one complex editor in the Page tool in the future, beyond the grid layout editor supported now. For example, any item that requires a form response (like quiz questions or problems). That being the case, I need a filter to see if the content element is simple, ie, doesn't require programmatic editing support. I'll convert isEditable() to isSimple(). Changes done. Changed construction of select element in NewIemProducer. Now produces a drop down list of content types that exclude grid pages and structured text.
Starting work on EditItemProducer. A new object is needed to bundle information about a content item that's being edited or created. If edited, then it has a ContentResource. If new, then we know it's collection id, name, and description.
There is a convention around creating identifiers for content resources. If it's a file, the name of the file is used in the identifier. This eases URL creation, I believe.
From looking at the code, it looks like I can use the Item object to bundle information about the content item. After all, it's used for pretty much the same purpose in a sequence. All that's needed are some minor tweaks in the implementation to cache a ContentResource (if it's being edited). A new Item creation method will also be needed in SequencerService. Added. Fixed up code in ItemImpl so that it doesn't assume that a content resource exists for it.
Ready to code up EditItemProducer.
Next Steps
- Editing properties and content. - in progress
- isEditedable() methods on content element handlers. - done
- getName() on handlers - done
- getType() on handlers - done
- editContent() on handlers
- saveContent() on handlers
- editParameters() on handlers
- saveParameters() on handlers
- Get edit content to work
- Get edit parameters to work
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 14, 2008
Checked in previous work. SVN Rev. 46743
Added code to PageObjectView to add an edit link to content items if they are "simple".
Modified EditItemProducer to create an Item on NEW or EDIT. From this, the title and description are shown.
Now that I see these two appearing in the view, I realize that users will want to edit these as well.
After some amount of thrashing, got the cancel link to display and work.
Added isParametersEditable() and isContentEditable() flags to all handlers.
Put in stubs for edit content and edit parameter form elements. Stubs work just fine.
Started work on editParameters() in the content handlers. Focusing on images first, because their parameters are simple.
Got the basics of editParameters() working. Stubbed out methods in all content handlers and implemented a pair of parameters for CEImage - height and width. Here's a picture:
This works by using an out of band agreement between the template and the editParameters() implementation for that content element. The template looks like this:
<form method="#" rsf:id="edit-form"> <table border="0" cellpadding="2"> <tr> <td align="right"><span rsf:id="edit-name-label">Name label here.</span></td> <td align="left"><input rsf:id="edit-item-name" type="text" name="name" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-desc-label">Description label here.</span></td> <td align="left"><input rsf:id="edit-item-desc" type="text" name="desc" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label">Parameter 0:.</span></td> <td align="left"><input rsf:id="edit-input" type="text" name="content" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p0">Parameter 0:.</span></td> <td align="left"><input rsf:id="edit-input-p0" type="text" name="p0" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p1">Parameter 1:.</span></td> <td align="left"><input rsf:id="edit-input-p1" type="text" name="p1" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p2">Parameter 2:.</span></td> <td align="left"><input rsf:id="edit-input-p2" type="text" name="p2" size="40"/></td> </tr> <tr> <td align="right"><span rsf:id="edit-label-p3">Parameter 3:.</span></td> <td align="left"><input rsf:id="edit-input-p3" type="text" name="p3" size="40"/></td> </tr> </table> <input rsf:id="edit-item-submit" type="submit"/> <a rsf:id="cancel-link"><span rsf:id="st-cancel-name">Cancel Link</span></a><br/> </form>
The form has input elements for up to four parameters (we may need as many as eight, but four is good for now). The handler doesn't use them, they don't show up in the UI view. There are inputs to edit the name and description. These are created in EditItemProducer. This is followed by a single field for content editing (not implemented yet). The come the four parameter fields. What parameters are handled by what fields is another agreement, this time between editParameters() and saveParameters() - to be implemented. At the moment, the code doesn't retrieve existing values, but that shouldn't be hard.
I think I'm going to need some kind of extension to the Item object as well. It needs to hold temporary values until everything is finally saved. It will have space for temporary parameter values, changed names and descriptions, content, etc. Previewing modified content before saving will be a challenge.
Next Steps
- Editing properties and content. - in progress
- isParametersEditable() on handlers - done
- isContentEditable() on parameters - done
- editParameters() on handlers - done
- saveParameters() on handlers
- Get edit parameters to work - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Preview edit changes
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar.15, 2008
Created PreviewItemProducer, PreviewItemParameteters, and preview.html.
Added these to SVN.
Edited PreviewItemProducer to show stubbed title.
Edite PreviewParamters to hande these fields: name, desc, content, p0, p1, p2, p3.
Changed EditItemProducer to refer to PreviewItemProducer in the form.
Form now links to stubbed PreviewItemPage.
Item currently has the following object variables:
private String resourceId = null; private String name = null; private String type = null; private String description = null; private Layout layout = null;
In addition to these, we're going to need the following in an EditItem class:
private String collectionId = null; private String content = null; private String p0 = null; private String p1 = null; private Layout p2 = null; private Layout p3 = null;
Created EditItem (API) and EditItemImpl.
Implemented both. Added both to SVN.
Created SequencerService.createEditItem() in two flavors (edit and new).
Added saveParameters() to content element handlers.
Added code to PreviewItemProducer to call saveParameters().
Compiles, needs to be tested. Implement save image parameters.
Implemented preview - image shows in preview page. It was pretty simple, just needed to prune down the ViewPageProducer logic, since this won't ever show a Sousa page.
Now I need to add parameters to content images display. This could be a bit tricky, since the properties are not stored out to the resource in preview. I might be able to use instanceOf to detect an EditImage being passed into displayContent(), then pick up the local values instead of the stored values.
Next Steps
- Editing properties and content. - in progress
- saveParameters() on handlers - done
- Get edit image parameters to work - done
- Preview edit changes - done
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Save parameter changes
- Implement parameters in remaining content handers (besides image).
- Show parameters in displayContent() handlers.
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 16, 2008
Started work on using parameters in preview image. I think the saveParameter() is misnmaed, because I'm going to need to actually save parameters back to the ContentResource later. Perhaps something like catchParameters(). Something similar will be needed for content as well. This is turning to be a bit more complicated than I originally envisioned. It will work, but somehow, it should be simpler.
Defined constant key names in ContentElement.
Finished coding of parameter inclusion in CEImage.displayContent().
Some kind of problem with the say I am decorating the RSF component. It rendered as:
<img width="null" height="null" src="http://localhost:8080/access/content/group/ContentTest/Aikido/seminar.jpg"/>
Heh. I didn't implement saveParameters(). Duh.
Breakdown. The saveParameter() method takes a ViewParameters() object, which I was going to up-cast into PreviewParameters. Doing so would create a dependency on sousa-page-tool, which I don't really want. I'd like for this UI code to be completely independent of any tools, though it is tied to them by conventions and protocols.
Sometimes, all you have to do is walk away from the code and things get better. Over dinner, I realized that I don't need to call saveParameters() in PreviewProducer. Just make sure all the values get into the EditItem object. This can be done without a priori knowledge of what parameters are supported for a particular content item. Just copy them all! Even empty values. They are all there, so why not? Then, when it comes time to either display or save them, the specific content handler will know which ones are good and where they belong.
Image now previews with parameters.
Next Steps
- Editing properties and content. - in progress
- Implement parameters in remaining content handers (besides image). - done
- Re-edit parameters
- Save parameter changes
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Show parameters in displayContent() handlers.
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 17, 2008
Implemented Change (re-edit). Works fine. Some modifications to the template.
Implemented Cancel. Works, goes back to PageObjectProducer with folders open – nice touch! I have to add that on all cancels.
This leaves saving the EditItem and clean up of cached objects.
Changed saveParameters() on all handlers to only take an EditItem as an argument. That's all that's needed.
Everything is in place to save objects, but the implementation in CEImage (etc). There is a bit of a catch to handle, since if there is not ContentResource in place (the create item case), then we can't update / initialize parameters (properties).
Created save() and saveParameter() methods in EditItem. This greatly simplifies adding content handler, since the content resource will be created if not present, then the parameters can be saved out to statically defined property names. CEImage.saveParameters() is implemented as follows:
public void saveParameters(EditItem item) { item.saveParameter (ContentElement.PARAM_HEIGHT, item.getP0()); item.saveParameter (ContentElement.PARAM_WIDTH, item.getP1()); }
This will the pattern for all saveParameter() methods in content handlers.
Need to implement EditItem.save() and EditItem.saveParameter() and all will work.
I have implemented the code needed to save resources out into content resource properties IF the resource already exists (this is the edit case). If the content resource doesn't exist, edits are lost (thrown away). Code tested and works! Scaled a picture to 50% of it's regular size. Shows up as 50% in page viewer.
Some additional instructions and tips will benefit the user. I might add a short instruction line at the top of the parameters block in EditItemProducer, and a tips column, too. Moved height and width labels off into the message bundle. Implemented tips and added height and width tips to the message bundle.
Implemented the border parameter in CEImage.
Fixed setup of edit parameter forms to pull old values into the form. Added getProperty() to EditItem.
There is a problem with the border attirbute. It doesn't show up in the preview or view. I think it be a problem with style sheets. My books indicate that the border attirbute is deprecated in favor a style, but it's still implemented in Firefox (etc.).
Next Steps
- Editing properties and content. - in progress
- Re-edit parameters (change) - done
- Add parameter tips. - done
- Save parameter changes - done
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 18, 2008
Couldn't figure out what the problem with borders on images was. Tried to render it as a style, but that didn't work. Dropped it from the code, desupporting borders as a parameter.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrated to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 19, 2008
Had a Chat with Antranig on Mar. 19, 2008 on file upload.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
- Look into adding reorderer Fluid component.
- Add media objects.
Mar. 24, 2008
In order to create new content items via Sousa, I'm going to have to support file upload. In order to do an upload, I need to use a POST form. RSF uses the Spring file upload resolvers and there is an example on the RSF site. This is documented in a Chat with Antranig on Mar. 19, 2008.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
Mar. 25, 2008
Downloaded the TestRSFComponents example.
The file upload form has to be set up as a POST form with a multipart encoding:
<form rsf:id="basic-form" method="post" enctype="multipart/form-data"> <input type="file" name="fileupload" /><br/> </form>
(This comes from the example in an edited form) It's interesting to note that the file input field doesn't have to be generated by RSF, as long as the field name is reflected in the view parameters. This is likely so because this field is never initialized, unlike text or select fields.
In the Sousa Page tool, the form is displayed in EditItemProducer and the submit action is handled by PreviewProducer. As such, it is PrevewProducer that will have to be wired up to extract the uploaded file from the multi-part enclosure and save it out to some kind of temporary file on the server.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
Apr. 3, 2008
Time to tackle content editing starting with file upload. Gonna need to add a couple more methods to ContentElement:
public void editContent(UIContainer tofill, String templateIdBase, EditItem contentItem); public void saveContent(EditItem item);
These parameters may not be right. Stubs added to all content handlers and compile.
I'm going to push the "New Item" path using video as the test case. I've got a clip of Megan May with the Sakaiger to use.
Changed the edititem.html template to use POST instead of GET. This is necessary to support file upload:
<form rsf:id="edit-form" method="post" enctype="multipart/form-data"> <table border="0" cellpadding="2"> ... Name and description fields go here ... <tr> <td align="right"><span rsf:id="edit-label">Content:</span></td> <td colspan="2" align="left"> <input rsf:id="edit-input-text" type="text" name="content" size="60"/> <input rsf:id="edit-input-file" type="file" name="content" size="60"/> </td> </tr> ... Parameter fields go here .... </table> </form>
Note that there are two flavors of content input at this time: text and file. Since only one or the other can be used, I think I can get way with using the same name (content). Later, other kinds of input might be used here such as textarea or a structured text editor. That can be worked out later.
Added editContent() and saveContent to ContentElementHandler. The following screen results from starting the creation of a new video item in a folder:
That was pretty easy. Now for the hard part. I need to add support for the multi-part enclosure resolver. RSF uses the resolver that comes with Spring and there is an example (see above). It should just be a matter of following the example. Things are never that easy, however. For starters, this is the only POST operation in all of Sousa. I'm not sure how it will affect state and use of back button. Generally, you can't use the back button to go back past a POST operation, but who knows? Antranig is a genius. Maybe he fixed that.
Confirmed that editing of parameters still works. That's good news.
Besides setting up the multi-part resolver, the file upload demo defines an action handler for submit:
UICommand.make(form, "submitfile", "#{uploadaction.submit}");
"uploadaction" is a bean defined in the request scope file. Although the code isn't very clear, it looks like the parts of the submit are made available to the action handler as a map, presumably keyed by field names. The EditItem should be cached in the user's session, so it's possible to collect the edited content as it comes in, and save it off there. However, leaving large objects (like a video file, for example) in memory is NOT encouraged by Sakai. It needs to be moved out of memory into some form of temporary storage. Too bad CHS doesn't have explicit support for temporary files. I think I'm going to file a Jira request for this ( - SAK-13320Getting issue details... STATUS ).
Created UploadBean.java based on the bean included in the RSF example. This will handled the submit action. The UploadBean should come into scope when the request-response is being processed. As such, it should be available to the producer when it comes time to fill the component tree. It's going to need some careful Spring wiring. The multi-part map takes the place of the ViewParameters object. This is still present, but is not being used to resolve request parameters. They should all be in the map.
I note in the example that the upload bean is injected into the ResultsProducer. This means that whatever is extracted from the forms submission can be present in this bean and made available to show results.
Jim Eng on Temporary Resources
Look at the citations helper:
Find the implementation of the method with this signature:
protected ContentResource createTemporaryResource(ResourceToolActionPipe pipe)
The ContentEntity in the pipe is the collection in which the CitationList is being created. The temporary resource is created there. If the user's session is lost before they are done creating the Citation List, the temporary resource will be there named "New Citation List" or "New Citation List-1" or "New Citation List-2" or whatever, so the user can recover work they've done. Notice that we tried to hide it. There are problems with that.
The temporary resource is deleted if the user clicks "continue" or "cancel" while in the citation helper. You can see where that's done by searching for the doFinish and doCancel methods (or by searching for "removeResource").
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers
- saveContent() on handlers
- Get edit content to work
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
Apr. 4, 2008
Added bean definition for UploadBean. All the bean does is print out a message to stdout at this point. I just want to see if it is getting invoked correctly. Display logic in PreviewProducer has been commented out.
Well, it transitions to the preview page with no errors, but it doesn't look like the submit action was invoked.
Re-started tomcat. I didn't see any Sousa-related errors go by.
This might be part of the problem. Here is the render HTML for EditItemProducer:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/preview" enctype="multipart/form-data" method="get">
Note that the method has been changed to GET.
It looks like I may have coded the UIForm in EditItemProducer. It still refers to a ViewParameters object, which explains why that appoach still seems to work. I also note that text can be uploaded into the action handler by associating an EL string with the UIInput. That could be how other parameters are handled.
Ok, this looks better:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/edititem" enctype="multipart/form-data" method="post"> <input type="hidden" name="op" value="new" /> <input type="hidden" name="type" value="video" /> <input type="hidden" name="name" value="Sakaiger" /> <input type="hidden" name="desc" value="Megan with Sakaiger" /> <input type="hidden" name="id" value="/group/ContentTest/Some Stuff/" /> ...
Ok, I got an error when I tried to sumbit the form:
2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key Fast track action value uploadaction.submit> 2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key name value Sakaiger> 2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key desc value Megan with Sakaiger> 2008-04-04 11:45:35,711 INFO (PostDecoder.java:79) - <PostInit: key edit-item-name value Sakaiger> 2008-04-04 11:45:35,727 WARN (RSFActionHandler.java:213) - <Error invoking action> Target exception of class java.lang.SecurityException Successive lines until stack trace show causes progressing to exception site: Error invoking action --> Writing to path content is not permissible - make sure to mark this path as request addressible - http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=RequestWriteableBean java.lang.SecurityException at uk.org.ponder.mapping.DARApplier.checkAccess(DARApplier.java:116) at uk.org.ponder.mapping.DARApplier.applyAlteration(DARApplier.java:384) at uk.org.ponder.mapping.DARApplier.applyAlterations(DARApplier.java:458) at uk.org.ponder.rsf.state.RSVCApplier.applyAlterations(RSVCApplier.java:82)
It seems very strange that I'd get a security violation error from the Wiki Tool.
Looking back at the two rendered forms above, I note that one has a "preview" page while the more recent one designates "edititem" as the target page. Perhaps the existing page is assumed.
Changing the ViewParameters even to a SimpleViewParameters causes the method to change back to GET, even though the action is now right:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/preview" enctype="multipart/form-data" method="get">
I need to do some more research on POST forms in RSF, obviously.
Here's an interesting piece of information from UICommand:
You may NOT set the (navigation) target of a UICommand, by RSF design it will ALWAYS (in the case of an HTTP/HTML render system) post to the same URL as the page on which it is contained.
That certainly explains why it wants to go to the edititem template - though not why I got a security error.
This will require re-thinking the state diagram and flow of information in editing.
Next Steps
- Editing properties and content. - in progress
- editContent() on handlers - done
- saveContent() on handlers - done
- Get file upload to work.
- Get edit content to work.
- Implement parameters in remaining content handers (besides image).
- Virtual lab media type.
- Finish VRML media type.
- Create second Sousa release.
- Migrate to 2.5.x (add Maven POM file).
April 7, 2008
Had a [ Chat with Antranig April 8, 2008] on POST forms in RSF. The upshot of the discussion is that I need to create an register a NavigationCase to forward the results of the file upload form to PreviewProducer. The documentation on RSFwiki is pretty clear. I register a navigation case and then return a string out of my action handler. This causes the registered producer to be invoked as if a GET request had been made. I may even be able to pick results out of a ViewParameters object. Consider this snip from the NavigationCase documentation on RSFwiki:
public List reportNavigationCases() { List l = new ArrayList(); l.add(new NavigationCase("added", new SimpleViewParameters( ItemsProducer.VIEW_ID))); return l; }
I could just as easily register a PreviewParameters object instead of a SimpleViewParameters, I would think.
FCKEdit and TinyMCE controllers may require the use of a POST form, too, since the text may be arbitrarily long.
April 20, 2008
A closer look at the file upload demo indicates that each field in the form is going need it's own variable in the action handler bean. The text field in the example does, though the file field doesn't, it relies on the submit action and a map created.
There really isn't a lot going on here, that I can see. The text fields are stuffed into bean variables, including the one indicated by a select control.
The ViewParameters passed into EditItemProducer may likely be causing a problem, especially on subsequent transactions. This may be responsible for the fossilized fields showing up in the rendered HTML source.
One strategy that might be workable is to convert the NewItem template into a POST. Then handle the submit folding it into an EditItem object held in the session state, then use a Navigation Case to forward control to EditItemProducer. This might eliminate the need for a ViewParameters object coming into EditItem.
Here is the key part of the rendered HTML of edititem:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/edititem" enctype="multipart/form-data" method="post"><input type="hidden" name="op" value="new" /> <input type="hidden" name="type" value="video" /> <input type="hidden" name="name" value="Sakaiger" /> <input type="hidden" name="desc" value="Megan with sakaiger" /> <input type="hidden" name="id" value="/group/ContentTest/Some Stuff/" /> <table border="0" cellpadding="2"> <tr > <td align="right"><span >Name:</span></td> <td colspan="2" align="left"> <input value="Sakaiger" type="text" size="60" name="edit-item-name"/><input type="hidden" name="edit-item-name-fossil" value="istring#{name}Sakaiger" /> </td> </tr> <tr > <td align="right"><span >Description:</span></td> <td colspan="2" align="left"> <input value="Megan with sakaiger" type="text" size="60" name="edit-item-desc"/><input type="hidden" name="edit-item-desc-fossil" value="istring#{desc}Megan with sakaiger" /> </td> </tr> <tr > <td align="right"><span >Select a video file to upload:</span></td> <td colspan="2" align="left"> <input value="" type="file" size="60" name="edit-input-file"/><input type="hidden" name="edit-input-file-fossil" value="istring#{content}" /> </td> </tr> </table> <input value="Submit" type="submit" name="command link parameters&Submitting+control=edit-item-submit&Fast+track+action=uploaditem.submit"/> <a href="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/page?save=false&id=%2Fgroup%2FContentTest%2FSome+Stuff%2F"><span >Cancel</span></a><br /> </form>
A couple of observations:
1. "name" and "desc" from the ViewParameters conflict with fields defined in this POST form. That's easy to fix, just change the names.
2. Duplicate input fields are being created for each of the POST form fields, one "fossilized". Why is that?
3. The submit button seems to be ited to uploaditem.submit, which is what we expect. So why isn't it called on submit?
Changing the field names might be a good first step. Chances are the ViewParamters will continue to capture the old values.
I think it might also be useful to conduct a more isolated example. Create a standalone app that just uploads a file into CHS using a form similar to the one defined for EditItem. That will allow me to experiment with file upload and POST operations. With that success in place, I can re-examine the workflow in Sousa Page tool and figure out how to upload new media files.
Created the start of a new tool in RSFExamples called ex5-post-form. I'll used this to test posting of simple information and file upload.
April 21, 2008
Changed the name of the example to rsf-ex-5. Compiled and ran it. Runs fine, but still uses a GET form.
Form changed to be POST:
<form method="POST" rsf:id="hello-form"> <span rsf:id="hello-instructions" style="font-weight: bold;" >Hello instructions goes here.</span><br/><br/> <span rsf:id="first-name-label">Name label here.</span> <input rsf:id="first-name" type="text" name="first" size="40"/><br/> <span rsf:id="last-name-label">Description label here.</span> <input rsf:id="last-name" type="text" name="last" size="40"/><br/><br/> <input rsf:id="hello-submit" type="submit"/> </form>
I'm not going to make any changes to the layout or fields in the form. This will better illustrate to to students how to compare GET with POST forms.
The receiving form bean is coded as:
class FormBean { public String first = null; public String last = null; public String submit() { System.out.println ("**** FormBean Submit."); return "second"; } }
It can't get much more simple than that!
The code for MainProducer.fillComponents() is:
UIForm newForm = UIForm.make(tofill, "hello-form"; UIMessage.make(tofill, "hello-instructions", "hello_instructions"); UIMessage.make(tofill, "first-name-label", "first_name_label"); UIInput.make(newForm, "first-name", "#{formbean.first}"); UIMessage.make (tofill, "last-name-label", "last_name_label"); UIInput.make(newForm, "last-name", "#{formbean.last}"); UICommand.make(newForm, "hello-submit", "Submit", "#{formbean.submit}");
Note that the ViewParameters parameter to UIForm.make() has been eliminated and a UICommand has been added to link the submit button to a method in the FormBean. The two text fields should now be injected into the first and last properties of FormBean.
I defined the form bean in requestContext:
<beans> <!-- Define the action handler bean. --> <bean id="formbean" class="org.sakaiproject.tool.simple.components.FormBean" /> </beans>
Updated the MainProducer and SecondProducer code. All that's needed is to add the NavigationCaseReporter in MainProducer to forward request display to SecondProducer. Coded as:
public List reportNavigationCases() { System.out.println ("***** MainProducer.resportNavigationCases"); List caseList = new ArrayList(); caseList.add(new NavigationCase("second", new SimpleViewParameters (SecondProducer.VIEW_ID))); return caseList; }
Couldn't acess the tools from Mercury. Looks like the application didn't start up correctly. That usually means that there is a Spring error somewhere, likely in my applicationContext file. Closing </bean> tag was mispelled. Several other problems corrected, all in the applicationContext. Now compiles and displays the first view.
A new error is appearing:
Error getting constructor for class org.sakaiproject.tool.simple.components.FormBean --> org.sakaiproject.tool.simple.components.FormBean.<init>() java.lang.NoSuchMethodException: org.sakaiproject.tool.simple.components.FormBean.<init>()
Ha! The FormBean class wasn't declared as public. It took a careful look to find that one.
Form comes up with out error now.
Oh boy! Now I get the same error as in Sousa Page tool:
Target exception of class java.lang.SecurityException Successive lines until stack trace show causes progressing to exception site: Error invoking action --> Writing to path formbean.first is not permissible - make sure to mark this p ath as request addressible - http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=R equestWriteableBean
Let's try adding settors.
No help, same error message. However, I did make a bit of a break through. That's a URL in the error message referring to the RSF Wiki! Doh!
If I read it right, I need to add my form bean to this to the list of request addressible beans in the applicationScope:
<bean parent="requestAddressibleParent"> <property name="value" value="hellobean,formbean"/> </bean>
Significant progress. Form now goes to SecondProducer. The FormBean.submit() method is being called. However, an instance of the form bean is not being injected into SecondProducer.
Antranig tells me that the bean is deallocated before the second producer is reached. This producer is actually a separate request cycle to ensure bookmarkability and back button works. He indicated that there was a way to capture some POST data and force it into a ViewParameters before the primary request cycle finishes. This could be passed off to the secondary view. While this work work for simple data (names, etc.), it won't work for files. That's probably ok.
April 22, 2008
Did a search on RSFWiki for Resulting View Bindings. It seems that this happens in the NavigationCase code. The navigation case code in Ex. 5 is:
public List reportNavigationCases() { System.out.println ("***** MainProducer.resportNavigationCases"); List caseList = new ArrayList(); caseList.add(new NavigationCase("second", new SimpleViewParameters (SecondProducer.VIEW_ID))); return caseList; }
Note the creation of SimpleViewParameters. This could be any ViewParameters object. If the handler bean is injected into the producer with the navigation case, it's data will be available before the end of the intial request, thus allow POST data to be communicated to the secondary view via GET parameters. This is very convoluted, but should work. Nowever, I do note that MainProducer.reportNavigationCases() is called before the request is processed. That might mean that the FormBean isn't initialized yet.
To make this work, I need to inject the FormBean into MainProducer.
See also Chat with Antranig April 22, 2008
April 24, 2008
Additional conversations with Antranig suggest one of two approches for handling POST forms (file upload): handle the request in the same producer as the form (the default), or use a navigation case to forward resulting display. If the later, data is going to have to be stored in session state.
The current content editing portion of EditItemProducer looks like this:
<tr> <td align="right"><span rsf:id="edit-label">Content:</span></td> <td colspan="2" align="left"> <input rsf:id="edit-input-text" type="text" name="content" size="60"/> <input rsf:id="edit-input-file" type="file" name="content" size="60"/> </td> </tr>
By moving this part into it's own form on the same page, uses will be able to uploade a file (or editing content) in place on the same page. Personally, I think that this is kinda confusing from a UX point of fiew, but RSF is really forcing me into this kind of approach. The alternatives are signficantly more complex.
This page needs to be split into three sections: General Parameters, Content, and Media Parameters. General parameters should always be displayed and editable. Content is displayed for new items or dropped down to change in the case of edit. Finally, Media Parameters are optionally displayed based on the media type. This could be done as three separate menus that are all processed by EditItemProducer and then have a separate link to move off to Preview and final save. The only problem with this approach is that I'd need to check for changes to fields that have not been saved if the preview link is selected. Although, the preview will have the option to return to edit, if something was missed.
Added caching of form data into user session in FormBean. Removed injection of FormBean into SecondProducer. Modified code in SecondProducer to take data out of user session and display it. Compiles and runs correctly. This is about the best and simplest example of how to use a POST for via RSF. I need to move this into the training materials.
Made a back up to RSFExamples-042408.
Next up is to expand this example to include file upload!
Cloned Ex5 into Ex6. Base example compiles and runs.
Changed MainProducer to show a file input.
Changed FormBean to get a file (by extracting code fomr UploadBean in the RSF example).
Stubbed SecondProducer to show a default string. Allows us to see if we reach that view.
Compiles and first view comes up. Selectinng a test text file generates the following error in the FormBean:
2008-04-24 12:01:25,734 INFO (PostDecoder.java:79) - <PostInit: key Submitting c ontrol value hello-submit> 2008-04-24 12:01:25,765 WARN (RSFActionHandler.java:213) - <Error invoking action> Target exception of class java.lang.IllegalArgumentException Successive lines until stack trace show causes progressing to exception site: Error invoking action --> Error setting dependency multipartMap of bean formbean --> class org.sakaiproject.tool.simple.components.FormBean has no writeable prop erty named multipartMap java.lang.IllegalArgumentException: class org.sakaiproject.tool.simple.component s.FormBean has no writeable property named multipartMap at uk.org.ponder.rsac.RSACBeanLocatorImpl.createBean(RSACBeanLocatorImpl
Sigh. I edited the FormBean in Example 5, rather than Example 6. Another problem that arises from copy/paste/cloning.
Copied changes to the correct file. Restored code in ex5/FormBean.
It's starting to work. Second view displayed. The following entries made in catalina.out by FormBean:
**** FormBean Submit. **** FormBean: request type is action **** FormBean:: Map {} **** FormBean: Reqmap: command link parameters&Submitting+control=hello-submit&Fast+track+action=formbean.submit : [Ljava.lang.String;@3c5d62 2008-04-24 12:09:52,703 INFO (SakaiRequestParser.java:109) - <Got tool dispatcher id of sakai.rsf.ex6 resourceBaseURL http://localhost:8080/rsf-ex-6/ baseURL http://localhost:8080/mercury/sakai.rsf.ex6/mercury/ and Sakai PID 6e40fbab-4da9-45a1-002a-dfc253ad3f82>
This makes it look like the map is empty.
Looks like I may have missed adding the apache commons upload resolver, etc. in Maven. Copied from RSFWiki.
Added new dependencies, no help.
Working carefully through the example, but still no help. Map has no entries.
April 28, 2008
Was reading through the RSF Q&A section on file upload and had a look at the Spring documentation on CommonsMultipartResolver. The encoding type is mentioned. Perhaps that is my problem. I can add an ENCTYPE of "multipart/form-data", which my HTML books says is required for file upload. Darn. It's already there. Well, I guess that's not the problem.
I packaged up the example and sent it off to Antranig. Maybe he can see my problem.
Response from Antranig:
AntranigBasman: Looks like you failed to follow this excellent guide
AntranigBasman: http://bugs.sakaiproject.org/confluence/display/BOOT/File+Uploads+with+RSF
AntranigBasman: Looks like the key in this case is to configure the Sakai request filter correctly
mjnsakai: I wasn't aware of this excellent guide.
mjnsakai: But I can certainly fix the request filter.
No wonder it didn't work. My request filter didn't allow it to work!
Changed the request filter setup in web.xml to the following:
<filter> <filter-name>sakai.request</filter-name> <filter-class>org.sakaiproject.util.RequestFilter</filter-class> <init-param> <param-name>upload.enabled</param-name> <param-value>false</param-value> </init-param> </filter>
Viola! It works with the following results:
**** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@1503061} **** FormBean: Iterate over keys: **** FormBean: Reqmap: command link parameters&Submitting+control=hello-submit&Fast+track+action=formbean.submit : [Ljava.lang.String;@19857ee **** FormBean: upload report is null.
Not sure why it didn't iterate over the keys, but at least I have a map entry with something in it!
The map entries have a key and a value of type MultipartFile.
See http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/web/multipart/MultipartFile.html
If the size of this file is zero, it means the user didn't upload a file and left the field empty.
While I'm getting something, I'm not sure what it is. I get the following error when I try to cast the map entry results into a MultipartFile:
**** FormBean: Iterate over multipart map keys: **** FormBean: Multipart Exception java.lang.ClassCastException: [Ljava.lang.String; at org.sakaiproject.tool.simple.components.FormBean.submit(FormBean.java:63)
Looking over Steve Githen's example, he doesn't override the MultipartResolver strategy. I think I'll comment that out and see what happens.
No help. Tried several different object types all resulting errors of the form:
2008-04-28 23:18:43,007 INFO (RenderUtil.java:137) - <Unpacked command link key Submitting control value hello-submit> 2008-04-28 23:18:43,023 INFO (RenderUtil.java:137) - <Unpacked command link key Fast track action value formbean.submit> 2008-04-28 23:18:43,038 INFO (PostDecoder.java:79) - <PostInit: key Fast track action value formbean.submit> 2008-04-28 23:18:43,054 INFO (PostDecoder.java:79) - <PostInit: key Submitting control value hello-submit> **** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@1903892} **** FormBean: Iterate over multipart map keys: **** FormBean: Multipart Exception java.lang.ClassCastException: [Ljava.lang.String; at org.sakaiproject.tool.simple.components.FormBean.submit(FormBean.java:65)
This is weird. "[Ljava.lang.String" doesn't seem like a valid object type. Further, the info seems to suggest that an object of "CommonsMultipartFile" is present.
I think I found the problem. I was iterating over the reqmap instead of multipartMap.
Ok, progress. Results are:
**** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@1fb6021} **** FormBean: Iterate over multipart map keys: **** FormBean: Value of fileupload is Key is [fileupload] with a sizeof [24] and a name of [fileupload] **** FormBean: upload report is null.
Code can be changed to getOriginalFileName() to get the name of this item. I can also get the input stream and print the actual file contents, or just pass it over to ContentHosting.
April 29, 2008
Changed the FormBean code example to show information about the file being uploaded:
**** FormBean: Submit action. **** FormBean: Request type is action **** FormBean: Map entry count is 1 **** FormBean: Map {fileupload=org.springframework.web.multipart.commons.CommonsMultipartFile@16c5f1a} **** Formbean: size of file is: 24 **** Formbean: original file name is: test.txt **** FormBean: content type is: text/plain
Now I'm ready to save the contents in a state variable and show it on the SecondProducer page.
Saved the stream in the session state. There might be better ways to do this, but it seemed to work.
Coded SecondProducer to display the content.
Content is correctly displayed. Example full works at this point.
Backed up all examples. Folded these new examples (Ex5 and Ex6 into Sakai training.
Ready to use this information to get file upload working in Sousa now.
Modified web.xml to:
<!-- The Sakai Request Handler - modified to enable file upload. --> <filter> <filter-name>sakai.request</filter-name> <filter-class>org.sakaiproject.util.RequestFilter</filter-class> <init-param> <param-name>upload.enabled</param-name> <param-value>false</param-value> </init-param> </filter>
This seems a bit strange, since the parameter is set to false, but it works in the example so who am I to argue? Perhaps this disables the Sakai mechanism so that the RSF one can work.
Removed the multipartResolver from applicationContext. Not needed.
Changed Navigation Case Reporter to use SimpleViewParameters. Since everything needs to be in the user session, I don't need anything else.
Still getting RequestWriteableBean errors.
Checked the applicationContext definition carefully. It seems to be right.
The file field has an rsf:id. I'll try taking that out. it shouldn't be needed.
Ok, the error went away. I commented out the desc and id fields from template and the producer. The type, name, desc, and id fields are getting created as hidden fields, likely because the EditItemProducer implements ViewReporter. I might need slightly different names for the edit fields here, since they are included automatically and hidden. It might be worth trying to include properties in the UploadItemBean for these feilds and see if it fails again.
Changed the name of the editable fields to xname and xdesc in template and EditItemProducer.
Changed bindings in EditItemProducer to refer to #{uploaditem.xname} and #{uploaditem.xdesc}.
Added properties and setters in UploadItemBean.
This worked. Yes! Now I need to move on to extracting information into session state and forwarding it to the PreviewProducer.
Dealing with an uploaded file means putting it into a temporary resource somewhere. Ideally, this should be a hidden collection managed by it's own service. Just to test out the file upload, I'm going to punt on creating resources for the moment. I'll use EditItem.setContent() to set the original file name as the stubbed content.
Submit recoded as:
public String submit() { // Get the edit item and it's state values. Session session = SessionManager.getCurrentSession(); EditItem item = (EditItem) session.getAttribute (EditItemProducer.EDIT_ITEM); // Update changes to name and description. item.setName (this.xname); item.setDescription (this.xdesc); // Add the new file content to the edit item. CommonsMultipartFile mf = (CommonsMultipartFile)this.multipartMap.get("content"); String fn = mf.getOriginalFilename(); item.setEditContent (fn); // mf.getInputStream()); // I'll need this later to create the ContentResource. System.out.println("**** Sousa Upload Bean new name:"+this.xname); System.out.println("**** Sousa Upload Bean new description:"+this.xdesc); System.out.println("**** Sousa Upload Bean new file:"+fn); return "preview"; }
I should put a check into this code to see if the user didn't specify a file. It really screws things up if they don't, so I need to handle this error case. I could re-direct back to EditItemProducer, perhaps with some kind of error code in EditItem.
Results from above are:
**** Sousa Upload Bean new name:null **** Sousa Upload Bean new description:null **** Sousa Upload Bean new file:Sakaiger.AVI
Added a field count on multipartMap:
**** Sousa Upload Bean - field count: 1 **** Sousa Upload Bean - new name: null **** Sousa Upload Bean - new description: null **** Sousa Upload Bean - new file:Sakaiger.AVI
I'm seeing fossilized fields in my rendered EditItemProducer view. The names of the input field are being changed to the rsf:id and my names are shifted into hidden fields:
<tr > <td align="right"><span >Name:</span></td> <td colspan="2" align="left"> <input value="Sakaiger" type="text" size="60" name="edit-item-name"/> <input type="hidden" name="edit-item-name-fossil" value="istring#{uploaditem.xname}Sakaiger" /> </td> </tr> <tr > <td align="right"><span >Description:</span></td> <td colspan="2" align="left"> <input value="Megan with sakaiger" type="text" size="60" name="edit-item-desc"/> <input type="hidden" name="edit-item-desc-fossil" value="istring#{uploaditem.xdesc}Megan with sakaiger" /> </td> </tr>
May 3, 2008 (on the way to Moscow)
Fired up my Post form example (ex5) to have a look at the rendered HTML. It looks like this:
<form action="http://localhost:8080/mercury/sakai.rsf.ex5/mercury/main" method="post"> <span style="font-weight: bold;">Please enter your first and last name.</span><br /><br /> <span >First Name:</span> <input value="" type="text" size="40" name="first-name"/> <input type="hidden" name="first-name-fossil" value="istring#{formbean.first}" /> <br /> <span >Last Name:</span> <input value="" type="text" size="40" name="last-name"/> <input type="hidden" name="last-name-fossil" value="istring#{formbean.last}" /> <br /><br /> <input value="Submit" type="submit" name="command link parameters&Submitting+control=hello-submit&Fast+track+action=formbean.submit"/> </form>
Now lets have a look at Sousa Page:
<form action="http://localhost:8080/portal/tool/047b6bbc-5e46-4bbc-00d8-e90dddeb2998/edititem" enctype="multipart/form-data" method="post"><input type="hidden" name="op" value="new" /> <input type="hidden" name="type" value="video" /> <input type="hidden" name="name" value="Sakaiger" /> <input type="hidden" name="desc" value="Megan with sakaiger" /> <input type="hidden" name="id" value="/group/ContentTest/Some Stuff/" /> <table border="0" cellpadding="2"> <tr > <td align="right"><span >Name:</span></td> <td colspan="2" align="left"> <input value="Sakaiger" type="text" size="60" name="edit-item-name"/> <input type="hidden" name="edit-item-name-fossil" value="istring#{uploaditem.xname}Sakaiger" /> </td> </tr> <tr > <td align="right"><span >Description:</span></td> <td colspan="2" align="left"> <input value="Megan with sakaiger" type="text" size="60" name="edit-item-desc"/> <input type="hidden" name="edit-item-desc-fossil" value="istring#{uploaditem.xdesc}Megan with sakaiger" /> </td> </tr> <tr > <td align="right"><span >Select a video file to upload:</span></td> <td colspan="2" align="left"> <!--<input rsf:id="edit-input-text" type="text" name="content" size="60"/>--> <input size="60" name="content" type="file" id="edit-input-file"/> </td> </tr>
I don't have agreement between the input field names and the backing bean property names. Gonna try putting name attributes in the template for xname and xdesc.
That didn't change anything. The name was overridden with the rsf:id name. I think that's was going on here. It doesn't matter what I call it. What matters is the rsf:id tag name, and the names of the bean properties. So why do the come up as null in the bean?
I think I have found a bug. If I edit the xname and xdesc fields, they appear in the bean. If I leave them unchanged, they appear as null. This CAN'T be the correct behavior. The value should be injected into the bean from the form, even if no change occurs.
Now I have a design decision to make. I could merge the new item and edit item views together. Ah, a better idea. These values are already captured into the EditItem object being saved in the session state. I can update the values if they change, and leave them alone if unchanged. That should work.
This also implies that the whole line of inquiry on field names was a red herring. I don't need to call them xname and xdesc, though there is also the hidden fields of the same names. Shouldn't matter because RSF is overriding the names anyways.
Verified theorized behavior:
**** Sousa Upload Bean - field count: 1 **** Sousa Upload Bean - new name: Cute Sakaiger **** Sousa Upload Bean - new description: Megan with cute sakaiger **** Sousa Upload Bean - new file:Sakaiger.AVI
The name and desc fields were edited on the Edit Item view form. Both come through into the command bean. Also put in a display of the video file name into PreviewProducer which was correctly display. This is all good news since I don't have any blockers to move forward (after nearly a month and a half of frustration).
To the get preview working, I need to create a hidden resource and refer to it. Some kind of temp resource service is needed. Other people have used similar techniques, but there is nothing in the mainline to support it.
It's been so long struggling with file upload that I've completely lost my train of thought with respect to parameter editing. I think video has three parameters: height, width, and autostart. Added code for video parameters:
**** Sousa Upload Bean - field count: 1 **** Sousa Upload Bean - new name: Cute Sakaiger **** Sousa Upload Bean - new description: Megan with fierce sakaiger **** Sousa Upload Bean - new file:Sakaiger.AVI **** Sousa Upload Bean - parameter 0: 100 **** Sousa Upload Bean - parameter 1: 100 **** Sousa Upload Bean - parameter 2: true **** Sousa Upload Bean - parameter 3: null
Parameters are coming through ok. At this point, EditItemProducer is fully working. Now I need to get the PreviewProducer view working. After that comes save and one pass through the workflow will be operational. I need to go back and implement cut and paste content as an alternative to file upload.
May 4, 2008 (in Moscow)
Based on the code in EditItem, it looks like I have to create a ContentResource and then set the id for the EditItem. The design seems a bit muddled to me, thought it may be that I've forgotten how to use it (sad, since I wrote it). EditItem has a save() method, but it is unimplemented at this time. This will be the key piece of code that makes editing work, in some ways.
There is a question on where to put the code that creates a new ContentResource. If I put it in UploadItemBean, what happens if there is an error? One thing that could be done is to create an error page that would provide an error code and then send the user back to an appropriate point in the edit workflow.
Created EditErrorProducer and editerr.html. An error code (bundle key) is saved in the user session and picked up the EditErrorProducer view to display an error that can be localized. Added SVN tree.
Verified that transfer to EditErrorProducer view will occur if "editerr" is returned out of UploadItemBean.
May 5, 2008 (in Moscow)
Creating the temporary content resource must be handled carefully. I plan to create the resource with a GUID, with its real name, type, content, etc. At save time, this can be blasted on top of the old resource or re-id'ed into a new resource. No, that' won't work.
In the process of coding resource creation in UploadItemBean, I've decided that this really should be folded into the SequencerService. Anything that works directly with the ConentHostingService should be down below the SequencerService layer. By creating the resource directly in UploadItemBean, I'm violating separation of concerns.
Given an EditItem, the following operations will likely be needed:
- create a temporary resource
- update a temporary resource
- save the temporary resource into it's permanant form
Create can probably be folded into update, since it's a special case. Since save() already exists (though not implemented), this means that I'm adding one new method to EditItem: updateTemp(). That's not too bad.
I should read my own code more often. There is a saveProperty() method in EditItem that does most of what I need. What's really needed is a saveContent() method to update the content in the item. I'm creating this in two forms:
public void saveContent (InputStream stream); public void saveContent (bytes[] text);
This handles both cases (though there may be more in the future for special kinnds of editing, TBD).
Later that evening...
Implemented saveContent() for both stream and text. Changed internals of EditItemImpl around a bit so that I could easily get a resource and editResource creating if needed. This stuff should all be tested (naturally), as I've tinkered with the way EditItem works.
May 6, 2008 (in Moscow)
'Added call to ContentHanlder.saveParameters(). This should save parameters to the temporary content resource instance.
Uncommented display of content in PreviewProducer. In theory (heh), all the code needed to create a new video item is in place at this time.
Error:
Error invoking action --> Error invoking method submit in bean at path uploaditem.submit java.lang.NullPointerException at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:2726) at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:3046) at org.sakaiproject.content.cover.ContentHostingService.addResource(ContentHostingService.java:328) at org.sakaiproject.sousa.impl.EditItemImpl.createResource(EditItemImpl.java:374) at org.sakaiproject.sousa.impl.EditItemImpl.getResource(EditItemImpl.java:354) at org.sakaiproject.sousa.impl.EditItemImpl.saveParameter(EditItemImpl.java:280) at org.sakaiproject.sousa.util.CEVideo.saveParameters(CEVideo.java:142) at org.sakaiproject.sousa.util.ContentElementHandler.saveParameters(ContentElementHandler.java:194)
CHS.addResource() didn't like me passing it a null pointer for the content. Stubbed content to an empty byte array.
Collection id was null. Set it in the EditItem in EditItemProducer.
****** UploadItemBean: item name: Sakaiger ****** UploadItemBean: item coll id: null ****** UploadItemBean: item type: video
There is a problem with the way item types are stored. Currently, I'm saving image as "image", when it should be "image/gif". I need some way to map file endings to content types. CHS does this somewhere.
Well, that did the trick. Some solid progress. The preview is showing, but not the video image. Here is the rendered HTML:
<!-- Content elements for preview. --> <div id="element"> <div style="text-indent: 1em;">Sakaiger.AVI</div> <embed width="200" height="200" src="http://localhost:8080/access/content/group/ContentTest/Some Stuff/Sakaiger"/> </div>
The name of the item is correct (Sakaiger). The collection id looks right. No type is specified, which might cause a problem. The plug-in missing view is shown.
May 7, 2008 (still in Moscow)
Though more work is needed to get video types to work, I think I;m going to shift to using an image as a test case. In part, because the image attributes of height and width were working previously. It will allow me to test to see if they are still working when a new item is created.
Well, here's an interesting problem, the Writeable Bean security error is back. This is very strange since it works just fine for video, but now fails when I try to add an image.
More strangeness. The isEditable flag in CEImage is false. I shouldn't have been able to edit the image.
That is explained by the fact that the file field in the form doesn't have an rsf:id tag. It's always present.
I'm going to try to create the control via a UIInput call, rather than hard-wiring it into the template. This should work, but lord knows I have struggled with RSF POST forms.
Ok, adding the rsf:id tag caused the file upload field to disappear, now I'll add it back by adding the UIInput and changing the editable flag to true for images.
That worked. File upload field is now visible.
Found problem with WriteableBean, too. UIInput refers to "po" instead of "#{uploaditem.p0}". Need to use an RSF-EL to tie the field to the action handler bean. Nope. That theory was wrong. Problem still there. Ok, finally solved. I had to eliminate reference to the file upload field name, which was "content". Not just in the template, but in the UIInput call as well. Name field called as null.
However, image is not displayed in the preview. There is something wrong with the temp content or access to it. So the last two hours of work bring me up where I was with video, but now images are broken as well.
May 8, 2008 (Flight Moscow to Boston)
Fired up Sakai to have a look at what was created as a content resource in the file upload process. There is an entry in the Moscow collection, but it has no name, and a type of "image". It has a size of one byte, which is suspicious since the content was supposed to have been added to the resource after it was created.
Maybe not so baffling after all. It doens't look like I saved the content into the resource. I had originally stubbed this to put the file name into the EditItem, but it doesn't look like the content was ever updated to it.
There is also the matter of file extensions to MIME type mapping. I had a look through the content hosting service, especially the type registry, but I didn't see anything that supported mapping. I do recall this being present in Sakai somewhere, perhaps as part of the configuration variables. A search of Sakai files for "mime" reveals a mime type file managed by Samigo, and couple of classes in OSP. Checked sakai.properties - nothing there. The Resources tool handles this problem, but it didn't turn up in the search.
As it happens, there is already the start of a media type table in ContentElementHandler. Perhaps the best thing to do would be to re-design this table to handle extension to mime type mapping as well as being able to get the content handler from type. It's a bit tricky. This table supports the notion that certain types can be handled together, like image/jpeg and image/gif.
Rather than screwing up what's there, I've created a new list in ConentElementHandler to translate extensions into types. Eventually these two approaches should be merged. In a moment of supreme irony, I created an inner class after stated just yesterday that inner classes are NEVER needed. In this case, the inner class is a simple data structure consisting of a MIME string, file extension string, type name, and handler.
Created ContentElementHandler.getType () which takes a file extension and returns the registered MIME type. Had to change the API of saveContent() to take an optional newType. There is no setType() method currently. Content type is always gotten from the ContentResource. Since we really only know the final type when we are saving the content to a temp resource, it's logical to pass it in here.
Well, the good news is no exceptions. The bad new is no image, either. My trace msgs indicate no file was uploaded, though I did select one. The generated HTML in preview looks good:
<div id="element"> <div style="text-indent: 1em;"/> <img width="50%" height="50%" src="http://localhost:8080/access/content/group/ContentTest/Moscow/Canon"/> </div>
Note that even the image paramters are correctly applied.
No content resource was added to the Moscow collection, either.
File upload got broken somehow. It's not finding the "content" field name.
Thinking about this problem (while standing in line to board the airplane), I recalled deleting the name attribute on the file input field of the
form thinking that I didn't really need. Tried adding it back, but it didn't work.
It looks like the field name is now "edit-input-file". I'll try putting that into UploadItemBean and see if we can get this sucka to work.
SUCCESS!
Finally, after weeks of effort, it works. The temp content resource was corectly created, and displayed in the preview page with parameters in place.
I had to access the MultipartMap using the field name created by RSF based on the rsf:id tag I gave to the file input field.
The next logical step is to work on save. The temp resource shows up in the target collection, but it has no name. It might be best to give it some kind of temp name, just in case manual clean up is needed. This is just a matter of adding the Display Name property. May as well add description, too. Tested and works.
From the preview page, three actions are possible: re-edit the new item, cancel the whole thing, and commit the new item.
Re-edit means returning to EditItemProducer view.
Cancel means advancing to EditPageProducer view, deleted the temporary ContentResource, and deleting the EditItem object in the user session.
Save means advaning to EditPageProducer view, updating all data in the ContentResource, and deleting the EditItem object.
May 24, 2008 (Return to Boston from Athens, GA)
Looking at the code, it seems like save is already in place. What's missing is the cancel edit operation. Cancel should check for a temporary resource and delete it.
Yes, it seems that a new media item (image in this case) is being created correctly with attributes, but it has a (temp) name. It might be best to just not name it as temp and only handle the cancel action. Once created, the item can't be edited - throws exception.
Removed the "(temp) prefix on temporary resource items. Looks like cached EditItem object is cleared already.
Editing of any media object is broken. Editing a sousa page seems to be still working.
Here is the error when trying to edit a media item:
**** EditItemImpl: create resource name: null **** EditItemImpl: create resource coll id: null **** EditItemImpl: create resource type: null 2008-05-24 15:17:10,609 WARN (RenderHandlerBracketer.java:110) - <Exception rendering view: > java.lang.NullPointerException at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:2726) at org.sakaiproject.content.impl.BaseContentService.addResource(BaseContentService.java:3046) at org.sakaiproject.content.cover.ContentHostingService.addResource(ContentHostingService.java:328) at org.sakaiproject.sousa.impl.EditItemImpl.createResource(EditItemImpl.java:389) at org.sakaiproject.sousa.impl.EditItemImpl.getResource(EditItemImpl.java:360) at org.sakaiproject.sousa.impl.ItemImpl.getType(ItemImpl.java:116) at org.sakaiproject.sousa.tool.EditItemProducer.fillComponents(EditItemProducer.java:148)
There are two versions of getResource(): one in EditItem and one in Item. When editing an existing item, we need to call the super version in Item. Corrected code in EditItemImpl. It no longer crashes, but changes to the attributes are not saved, perhaps because it thinks that the resource has already been created.
Some clues:
**** PageObjectProducer: saving parameters. **** EditItemImpl: create resource name: null **** EditItemImpl: create resource coll id: null **** EditItemImpl: create resource type: null ***** EditItemImpl: Error when updating the resource: null **** EditItemImpl: create resource name: null **** EditItemImpl: create resource coll id: null **** EditItemImpl: create resource type: null ***** EditItemImpl: Error when updating the resource: null
Note that saveParameters() is getting called in Page Object Producer, but we get an error when the resource is updated. We shouldn't be creating a resource in saveParameters().
Looks like a similar kind of problem. EditItem.getResource() is called when Item.getResource() should be called. Added a check in EditItem.saveParameters() to call the appropriate one.
Now I'm getting a permissions violation, which is kinda weird considing I created all of these objects:
**** PageObjectProducer: saving parameters. ***** EditItemImpl.getEditResource: Permission violation on accesing resource item in sequence. **** EditItemImpl: Error when updating the resource in saveParameters(): null ***** EditItemImpl.getEditResource: Permission violation on accesing resource item in sequence. **** EditItemImpl: Error when updating the resource in saveParameters(): null
Added a debug line. Need to re-test.
When creating a new media item, the system prompts for name, desciption, and type. While type is necessary, it can be hard to remember what to name your resource until you select it in the next screen. It might be better to drop name and description from the NewItemProducer page, especially since it's present on the EditItemProducer anyways.
Cancel from edit item needs to be carefully handled. There are two cases:
- Cancel the creation of a new media item by deleting the temp content resource.
- Cancel the edit of an existing media object by not updating any changes to attributes.
To Be Done
- Remove temp label on new media items. – done.
- Delete resources and cached media item on cancel.
- Fix edit of attributes on a new media item. - no longer crashes, but does't update changes to attributes.
May 26, 2008 (Home Again!)
Made a change to getEditResource(), since it seemed to be getting an editId of null. This is where the security violations seemed to be arising from. They are gone, but can't edit and save now.
May 31, 2008
If parameters such as height and width are null, they are rendered as height="null". This cases the image (in this case) to be invisible. Added to code to check for null parameters. Still not displaying. Problem is deeper. The media type in CHS is "image" instead of "image/jpeg", which will cause a problem.
Oh, this code is truly screwed up. Creating a new media item creates FOUR! ContentResources, each with different ids. This is all tied in with tempId, which I'm beginning to suspect was a bad design approach. The original intent to was to create a temporary ContentResource (hence the tempId), and then delete it if not updated. However, I've drifted over to just creating the resources and deleting it later if canceled (though there may be problems with this approach, too).
Made EditItem.createResource() a public method. Called from upload bean now. getEditResource() no longer creates the resource if it doesn't exist.
Ok, we're getting close. Preview is working again. Multiple resources are no longer being created. However, I got a null pointer exception when I tried to re-edit the media item - a null pointer trying to create a resource. I think this is from having an empty file input.
Additional adjustments were needed in upload bean to handle the case where file is not being re-loaded on a re-edit. Image media types now seem to work completely. Likely more testing is needed. Cleaned up code.
To Be Done
- Cancel creation of new file based media.
- Cancel creation of text based media.
- Cancel edit of new file based media.
- Cancel edit of text based media.
- Delete media objects, page objects, and sequences.
- Finish other media objects and their parameters: structured text, flash.
- Implement MathML and Header.
- Test everything!
- Migrate to 2.5.x
- Sousa release.
- Enable CHS to launch a page into the page viewer.
- Add CHS action to edit a page view (layout).
- Look into enabling Entity Broker
- Look into adding reorderer Fluid component.
Jun. 3, 2008
Updated some of the documentation: Sousa Design, Adding New Content Elements, etc.
Checked code into SVN, rev. 49815
Implemented the Header media element.
Adjusted view.html so that media elements in a tile are top justified.
Worked on documentation, updated the to-do list, added SVG notes, updated Sousa History (with a new photo), etc.