HttpServletRequestWrapper lose multipart inputs values - java

I'm trying to develop a XSS Filter. All works fine, but the wrapper is losing the multipart fields.
After the filter, in the controller, when I try to obtain the value of a multipart field always is empty.
I have the following wrapper:
public class XSSRequestWrapperMultipart extends HttpServletRequestWrapper {
/** Constructor. */
public XSSRequestWrapperMultipart(HttpServletRequest aRequest) throws IOException {
super(aRequest);
ServletFileUpload upload = new ServletFileUpload( new DiskFileItemFactory());
try {
List<FileItem> fileItems = upload.parseRequest(aRequest);
convertToMaps(fileItems);
}
catch(FileUploadException ex){
throw new IOException("Cannot parse underlying request: " + ex.toString());
}
}
/**
* Return all request parameter names, for both regular controls and file upload
* controls.
*/
#Override public Enumeration<String> getParameterNames() {
Set<String> allNames = new LinkedHashSet<>();
allNames.addAll(fRegularParams.keySet());
allNames.addAll(fFileParams.keySet());
return Collections.enumeration(allNames);
}
/**
* Return the parameter value. Applies only to regular parameters, not to
* file upload parameters.
*/
#Override public String getParameter(String aName) {
String result = null;
List<String> values = fRegularParams.get(aName);
if(values == null){
//you might try the wrappee, to see if it has a value
}
else if (values.isEmpty()) {
//param name known, but no values present
result = "";
}
else {
//return first value in list
result = values.get(FIRST_VALUE);
}
return result;
}
/**
* Return the parameter values. Applies only to regular parameters,
* not to file upload parameters.
*/
#Override public String[] getParameterValues(String aName) {
String[] result = null;
List<String> values = fRegularParams.get(aName);
if(values != null) {
result = values.toArray(new String[values.size()]);
}
return result;
}
/**
* Return a {#code Map<String, List<String>>} for all regular parameters.
* Does not return any file upload parameters at all.
*/
#Override public Map<String, List<String>> getParameterMap() {
return Collections.unmodifiableMap(fRegularParams);
}
/**
* Return a {#code List<FileItem>}, in the same order as they appear
* in the underlying request.
*/
public List<FileItem> getFileItems(){
return new ArrayList<FileItem>(fFileParams.values());
}
/**
* Return the {#link FileItem} of the given name.
* <P>If the name is unknown, then return <tt>null</tt>.
*/
public FileItem getFileItem(String aFieldName){
return fFileParams.get(aFieldName);
}
// PRIVATE
/** Store regular params only. May be multivalued (hence the List). */
private final Map<String, List<String>> fRegularParams = new LinkedHashMap<>();
/** Store file params only. */
private final Map<String, FileItem> fFileParams = new LinkedHashMap<>();
private static final int FIRST_VALUE = 0;
private void convertToMaps(List<FileItem> aFileItems){
for(FileItem item: aFileItems) {
if ( isFileUploadField(item) ) {
fFileParams.put(item.getFieldName(), item);
}
else {
if( alreadyHasValue(item) ){
addMultivaluedItem(item);
}
else {
addSingleValueItem(item);
}
}
}
}
private boolean isFileUploadField(FileItem aFileItem){
return ! aFileItem.isFormField();
}
private boolean alreadyHasValue(FileItem aItem){
return fRegularParams.get(aItem.getFieldName()) != null;
}
private void addSingleValueItem(FileItem aItem){
List<String> list = new ArrayList<>();
list.add(aItem.getString());
fRegularParams.put(aItem.getFieldName(), list);
}
private void addMultivaluedItem(FileItem aItem){
List<String> values = fRegularParams.get(aItem.getFieldName());
values.add(aItem.getString());
}
}
All relative to the fRegularParams works fine, but the fFileParams always appears as null in the controller.
What can I do to keep the values?
Regards

If you see for fRegularParams, you are touching the getParameter() method of servlet lifecycle.
Here the parameters are already initialized in this phase.
For fFileParams you are trying to get params in constructor, which is too early considering lifecycle of servlet and filters.
Image for your reference:
Solution:
Can you try with method request.getParts() instead?
You can try this approach and override
https://github.com/spring-projects/spring-framework/blob/2f20d6322b7a0fcbbaa80280849e7c31fc78d4a9/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java#L131
Which internally deals with request parts.
https://github.com/spring-projects/spring-framework/blob/2f20d6322b7a0fcbbaa80280849e7c31fc78d4a9/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java#L91

Here "might" be your problem:
private boolean isFileUploadField(FileItem aFileItem){
return ! aFileItem.isFormField();
}
It's returning the opposite response of the boolean value (check the !). Remove it and test if that works.
Only if the FileItem.isFormField() that you can get the form parameter data.
private boolean isFileUploadField(FileItem aFileItem){
return aFileItem.isFormField();
}

Related

Spring RestTemplate exchange throws UnhandledHttpStatusException

Overview:
I am going to use RestTemplate to invoke a get request from external REST webservice.
My code is as follows:
#Slf4j
#Component("AccMemberDetailsApiControllerImpl")
public class AccMemberDetailsApiControllerImpl implements MemberDetailsApiController {
private static final String CONTENT_TYPE_HEADER_NAME = "Content-Type";
private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
private static final String USERID_PARAMETER_NAME = "userId";
private static final String VEHICLEID_PARAMETER_NAME = "vehicleId";
private static final ObjectMapper mapper = new ObjectMapper();
/**
* This constant is used to check whether or not the response from ACC is an empty JSON string
*/
private static final String EMPTY_RESPONSE = "{}";
#Value("${com.blss.memberServices.provider.posServiceURL}")
private String accPosServiceURL;
#Autowired
private RestTemplate restTemplate;
#Autowired
private AccTokenUtility accTokenUtility;
#Autowired
private ResourceMessage resourceMessage;
void setAccTokenUtility(AccTokenUtility accTokenUtility) {
this.accTokenUtility = accTokenUtility;
}
void setResourceMessage(ResourceMessage resourceMessage) {
this.resourceMessage = resourceMessage;
}
/**
* #see MemberDetailsApiController#getMemberDetails(String, String)
*/
#Override
public MemberDetailsModel getMemberDetails(String storeId, String membershipIdentifier) {
/**
* Getting CAD token
*/
String token = accTokenUtility.getCadToken();
/**
* Preparing the request
*/
HttpHeaders headers = new HttpHeaders();
// headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set(CONTENT_TYPE_HEADER_NAME, MediaType.APPLICATION_JSON_VALUE);
headers.set(AUTHORIZATION_HEADER_NAME, token);
HttpEntity<String> entity = new HttpEntity<>(headers);
/**
* Creating the dispatch URL by means of userId and vehicleId
*/
String dispatchURL = accPosServiceURL + "DispatchedEvent/{userId}/{vehicleId}";
/**
* Creating the URL variables and being valued by corresponding method parameters
*/
Map<String, String> parameters = new HashMap<>();
// parameters.put(USERID_PARAMETER_NAME, storeId);
parameters.put(USERID_PARAMETER_NAME, "mr2");
// parameters.put(VEHICLEID_PARAMETER_NAME, membershipIdentifier);
parameters.put(VEHICLEID_PARAMETER_NAME, "VEH1");
/**
* Calling the rest webservice and returning response with body of type {#link AccMemberDetails}
*/
ResponseEntity<String> response;
MemberDetailsModel memberDetailsModel = null;
AccMemberDetails accMemberDetails;
try {
response = restTemplate.exchange(dispatchURL, HttpMethod.GET, entity, String.class, parameters);
if (response == null || StringUtils.isBlank(response.getBody()) || EMPTY_RESPONSE.equals(response.getBody())) {
throw new ResourceNotFoundException(resourceMessage.getMessage(MEMBER_ERROR_NOT_FOUND, storeId, membershipIdentifier));
} else {
accMemberDetails = deserialize(response.getBody(), AccMemberDetails.class);
String accErrorMessage = accMemberDetails.getUserMessage();
if (!StringUtils.isBlank(accErrorMessage)) {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_ERROR_MESSAGE_FROM_API, "ACC", accErrorMessage));
}
memberDetailsModel = convert(accMemberDetails);
}
} catch (RestClientException e) {
handleExceptions(e, storeId, membershipIdentifier);
}
return memberDetailsModel;
}
/**
* This method is responsible for deserializing string REST response into an object of type {#link AccMemberDetails}
*/
<T> T deserialize(final String response, final Class<T> responseClass) {
try {
return mapper.readValue(response, responseClass);
} catch (IOException e) {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_ERROR_MAP_RESPONSE_OBJECT), e);
}
}
/**
* This method is responsible for converting an instance of type {#link AccMemberDetails} to an instance of type
* {#link MemberDetailsModel}
*
* #param accMemberDetails an instance of type {#link AccMemberDetails}
* #return an instance of type {#link MemberDetailsModel}
*/
MemberDetailsModel convert(AccMemberDetails accMemberDetails) {
MemberDetailsModel memberDetailsModel = new MemberDetailsModel();
memberDetailsModel.setEventId(accMemberDetails.getEventId());
memberDetailsModel.setMemberName(accMemberDetails.getMemberName());
memberDetailsModel.setMembershipNumber(accMemberDetails.getMembershipNumber());
memberDetailsModel.setMembershipLevel(accMemberDetails.getPricingLevel());
return memberDetailsModel;
}
/**
* This method is responsible for handling Exceptions may be thrown by ACC REST webservice
*
* #param e an instance of type {#link RestClientException}
* #param storeId an instance of type {#link String} and used in building exception messages
* #param membershipIdentifier an instance of type {#link String} and used in building exception messages
*/
private void handleExceptions(RestClientException e, String storeId, String membershipIdentifier) {
if (e instanceof HttpStatusCodeException) {
HttpStatusCodeException httpStatusCodeException = (HttpStatusCodeException) e;
HttpStatus httpStatusCode = httpStatusCodeException.getStatusCode();
if (404 == httpStatusCode.value()) {
throw new ResourceNotFoundException(resourceMessage.getMessage(MEMBER_ERROR_NOT_FOUND, storeId, membershipIdentifier), e);
} else if (500 == httpStatusCode.value()) {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_SERVER_ERROR, "ACC"), e);
} else {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_HTTP_STATUS_CODE_ERROR, "HttpStatusCodeException", "ACC"), e);
}
} else {
throw new InternalServerException(resourceMessage.getMessage(MEMBER_REST_CLIENT_ERROR, "RestClientException", "ACC"), e);
}
}
Problem
However I got UnhandledHttpStatusException after calling "restTemplate.exchange(dispatchURL, HttpMethod.GET, entity, String.class, parameters);" in the code snippet. the exception stack trace is as follows:
Caused by: org.springframework.web.client.UnknownHttpStatusCodeException: Unknown status code [443] null
at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:60)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:629)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:565)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:484)
at com.blss.retailServices.memberServices.controllers.impl.acc.AccMemberDetailsApiControllerImpl.getMemberDetails(AccMemberDetailsApiControllerImpl.java:110)
Now I would be grateful if anyone could suggest me a solution.
I called this webservice with curl by using "-v" in order to get more info in response. As a result, I got the same exception (443) from their side. So, It sounds like they should have a better exception handler to return meaningful exception messages.

How to export huge result set of a mybatis select query to csv?

Using MyBatis, I am getting close to 65,000 results from a select query within a mapper. I want to create a csv and send these results as a zip file to the UI call which will trigger the download dialog directly of the browser.
Upon searching, I understood that we need to use custom result handler in these scenarios. But the link to the example from ibatis seems to be removed http://code.google.com/p/mybatis/wiki/ResultHandlerExample leaving no accurate steps for me to use or implement it.
However, I have tried as below.
public class CSVExportRowHandler implements ResultHandler {
#SuppressWarnings("unchecked")
#Override
public void handleResult(ResultContext context) {
SRDContainer srdContainer = (SRDContainer) context.getResultObject();
System.out.println("Container: " + srdContainer.toString() + ", " + context.getResultCount() +", "+ context.isStopped());
for (StudentResultDetails srd : srdContainer.getStudentResultDetails()){
System.out.println("result: " + srd.getStudentName());
}
}
}
As the handleResult method must return void. On this note, I have the below queries.
I am able to print to the console only one record upon using this CSVExportRowHandler class. What happened to the rest of the records
(should have been 65k) ?
Is there any optimized way of doing this ?
How to trigger the download dialog of browser directly ? before that do I need to write the records to csv or I can stream the results to download ?
Here are my DAO and the jax-rs service for reference
DAO.java
public void exportSRD(HashMap<String, Object> params) {
SqlSession sqlSession = SessionFactory.getSession().openSession();
try {
CSVExportRowHandler handler = new CSVExportRowHandler();
sqlSession.select("getAssignmentSRDSession", params, handler);
} finally {
sqlSession.close();
}
}
Service:
#Path("/{reportType}/studentresultdetails/{function}/{sessionId}")
#GET
public void exportOrPrintUtil(#PathParam("reportType") String reportType, #PathParam("function") String function, #QueryParam("pageNum") Integer pageNum,
#QueryParam("pageSize") Integer pageSize, #QueryParam("sortOn") String sortOn, #QueryParam("sortOrder") String sortOrder,
#QueryParam("filterByName") String filterByName, #PathParam("sessionId") Integer sessionId) throws IOException {
HashMap<String, Object> params = new HashMap<String, Object>();
Object enableSort;
Object enablePrintOrExportFlag;
params.put("sessionId", sessionId);
params.put("enableSort", false);
params.put("enablePrintOrExportFlag", true);
params.put("filterByName", filterByName);
dao.exportSRD(params);
*********** WHAT TO BE RETURNED AS THE ABOVE dao.exportSRD(params) RETURNS VOID. HOW TO TRIGGER DOWNLOAD DIALOG FROM HERE. *****************
}
SRDContainer.java object
#XmlRootElement
public class SRDContainer implements Comparable<SRDContainer> {
private List<StudentResultDetails> studentResultDetails;
public SRDContainer() {}
public SRDContainer(
List<StudentResultDetails> studentResultDetails) {
super();
this.studentResultDetails = studentResultDetails;
}
public List<StudentResultDetails> getStudentResultDetails() {
return studentResultDetails;
}
public void setStudentResultDetails(
List<StudentResultDetails> studentResultDetails) {
this.studentResultDetails = studentResultDetails;
}
#Override
public int compareTo(SRDContainer o) {
return 0;
}
#Override
public String toString() {
return "SRDContainer [studentResultDetails="
+ studentResultDetails + "]";
}
public List<String[]> toStringArrayList() {
String[] array = new String[studentResultDetails.size()];
List<String[]> stringArrayListOut = new ArrayList<String[]>();
int index = 0;
for (StudentResultDetails value : this.studentResultDetails) {
array[index] = value.toFlatCSVString();
index++;
}
stringArrayListOut.add(array);
return stringArrayListOut;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((studentResultDetails == null) ? 0 : studentResultDetails
.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SRDContainer other = (SRDContainer) obj;
if (studentResultDetails == null) {
if (other.studentResultDetails != null)
return false;
} else if (!studentResultDetails.equals(other.studentResultDetails))
return false;
return true;
}
}
I am pretty new to jax-rs and mybatis.
Thanks !!!!
sessionID make your code too complicated , jackoffID as well. even with deferred loading (thanks to CGLib proxies). It gets just a little fuzzy, however, when discussing how to implement complex queries
select id, name, shortName, description
from tag

Contains method case-insensitive without major code changes?

Is there a way to ignore the case for the contains() method but at the same time leave the code snippet more or less the same?
/**
* This method returns a list of all words from the dictionary that include the given substring.
*
*/
public ArrayList<String> wordsContaining(String text)
{
int index = 0;
ArrayList<String> wordsContaining = new ArrayList<String>();
while(index<words.size())
{
if((words.get(index).contains(text)))
{
wordsContaining.add(words.get(index));
}
index++;
}
return wordsContaining;
}
here is the whole SpellChecker Class:
public class SpellChecker
{
private ArrayList<String> words;
private DictReader reader;
/**
* Constructor for objects of class SpellChecker
*/
public SpellChecker()
{
reader = new DictReader("words.txt");
words = reader.getDictionary();
}
/**
* This method returns the number of words in the dictionary.
*
*/
public int numberOfWords()
{
return words.size();
}
/**
* This method returns true, if (and only if) the given word is found in the dictionary.
*
*/
public boolean isKnownWord(String word)
{
int index =0;
while(index < words.size())
{
if(words.get(index).equals(word))
{
return true;
}
index++;
}
return false;
}
/**
* This method returns true if (and only if) all words in the given wordList are found in the dictionary.
*/
public boolean allKnown(ArrayList<String> wordList)
{
for(String word : wordList)
{
if(isKnownWord(word))
{
return true;
}
}
return false;
}
/**
* This method tests the allKnown method.
*/
public boolean testAllKnown()
{
ArrayList<String> testWords = new ArrayList<String>();
testWords.add("Abu");
testWords.add("Chou");
if(allKnown(testWords))
{
return true;
}
else
{
return false;
}
}
/**
* This method returns a list of all words from the dictionary that start with the given prefix.
*
*/
public ArrayList<String> wordsStartingWith(String prefix)
{
int index = 0;
ArrayList<String> wordsStartingWith = new ArrayList<String>();
while(index<words.size())
{
if(words.get(index).startsWith(prefix))
{
wordsStartingWith.add(words.get(index));
}
index++;
}
return wordsStartingWith;
}
/**
* This method returns a list of all words from the dictionary that include the given substring.
*
*/
public ArrayList<String> wordsContaining(String text)
{
int index = 0;
ArrayList<String> wordsContaining = new ArrayList<String>();
while(index<words.size())
{
if((words.get(index).contains(text)))
{
wordsContaining.add(words.get(index));
}
index++;
}
return wordsContaining;
}
The DicReader class simply takes a give text file and "Makes" a dictionary out of it. I'll put it up just in case:
public class DictReader
{
private ArrayList<String> dict;
private String filename;
/**
* Create a DictReader instance from a file.
*/
public DictReader(String filename)
{
loadDictionary(filename);
this.filename = filename;
}
/**
* Return the dictionary as a list of words.
*/
public ArrayList<String> getDictionary()
{
return dict;
}
/**
* Accept a new dictionary and save it under the same name. Use the new
* one as our dictionary from now on.
*/
public void save(ArrayList<String> dictionary)
{
try {
FileWriter out = new FileWriter(filename);
for(String word : dictionary) {
out.write(word);
out.write("\n");
}
out.close();
dict = dictionary;
}
catch(IOException exc) {
System.out.println("Error writing dictionary file: " + exc);
}
}
/**
* Load the dictionary from disk and store it in the 'dict' field.
*/
private void loadDictionary(String filename)
{
dict = new ArrayList<String>();
try {
BufferedReader in = new BufferedReader(new FileReader(filename));
String word = in.readLine();
while(word != null) {
dict.add(word);
word = in.readLine();
}
in.close();
}
catch(IOException exc) {
System.out.println("Error reading dictionary file: " + exc);
}
}
}
So the question is I need to check weather or not a given word contains a text snippet/substring which I have called "text" however the contains method for strings is case sensitive. I have done some research and noticed that to remove the case sensitivity you must import a specific library and the syntax for the new contains method is different and it does not play well with what I currently have as code. I was then wondering if there is a way to make contains() case-insensitive but preserve the structure of the code.
Make both strings lowercase(or uppercase)
public ArrayList<String> wordsContaining(String text)
{
int index = 0;
text = text.toLowerCase();
ArrayList<String> wordsContaining = new ArrayList<String>();
while(index<words.size())
{
if((words.get(index).toLowerCase().contains(text)))
{
wordsContaining.add(words.get(index));
}
index++;
}
return wordsContaining;
}

How to Access Underlying Document of a new Notes Email Before it is Saved

We have a Lotus Notes Plug-In, developed in Java. The current version of Notes we're supporting is 8.5.2.
This plug-in adds a button to the Notes UI. When the user clicks it, we present a window to the user, which allows the user to add the current item to our web-based application using web services. Everything works fine, except when the user tries to add a new email item.
The listener for the "click event" (if you will) needs to know the current document so that it can pass its field data to the web service call. In order to do that, a separate listener has been set up (DocumentContextService) which essentially gets invoked any time the input focus changes within the Notes UI.
DocumentContextService attempts to retrieve the URI of the current document. And that's where things fall apart. I am finding that an unsent email message has no URI. Further, there appears to be no way to get to the document and save it, so that I can obtain one.
Theoretically, this is by design. Oddly, I can see that the new document has a DocumentKey, so I know it exists (as a draft somewhere), but I cannot get to it. So there doesn't appear to be any way to access the document's data until it is actually saved.
Unless I'm wrong (and I very well could be). And there's the question: Is there a way to obtain the underlying document of a new email before it has been saved so that I can access its data (specifically, its fields)?
The code from the document context listener is below. The problem, again, is that the URI property always evaluates to an empty string for new emails.
package com.ibm.lotuslabs.context.service.internal;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import com.ibm.lotuslabs.context.service.document.IDocumentContext;
import com.ibm.rcp.jface.launcher.IURIProvider;
import com.satuit.sys.The;
/**
* Extracts document information about about a selection object. Represents the document within the DocumentSelection.
*/
#SuppressWarnings("deprecation")
public class DocumentContext implements IDocumentContext
{
private IWorkbenchPart part;
private Object obj;
private String label;
private URI uri;
private ImageDescriptor icon;
private Properties properties;
private String id;
/**
* Initializes a new instance of the DocumentContext class.
*
* #param part The current view part.
* #param obj The currently selected object.
*/
public DocumentContext(final IWorkbenchPart part, final Object obj)
{
this.part = part;
this.obj = obj;
// Is this object a URIProvider?
final IURIProvider provider = (IURIProvider)ContextUtil.getAdapterObject(obj, IURIProvider.class);
if (provider != null)
{
this.uri = provider.getURI();
this.label = provider.getTitle();
this.icon = provider.getImageDescriptor();
}
if (this.label == null || this.icon == null)
{
// Is this object a workbench adapter?
final IWorkbenchAdapter wba = (IWorkbenchAdapter)ContextUtil.getAdapterObject(obj, IWorkbenchAdapter.class);
if (wba != null)
{
if (this.label != null)
{
this.label = wba.getLabel(obj);
}
if (this.icon != null)
{
this.icon = wba.getImageDescriptor(obj);
}
}
if (this.icon == null)
{
final Image i = part.getTitleImage();
if (i != null)
{
this.icon = ImageDescriptor.createFromImage(i);
}
}
}
// Is this object a URI?
if (this.uri == null)
{
this.uri = (URI)ContextUtil.getAdapterObject(obj, URI.class);
}
// Is this object a PropertySource?
// (A document that isn't a URI provider may provide a URI in its properties.)
final IPropertySource prop = (IPropertySource)ContextUtil.getAdapterObject(obj, IPropertySource.class);
if (prop != null)
{
this.properties = buildProperties(prop);
}
}
/**
* Gets the ID of this instance.
* #return A string containing the ID.
*/
public final String getId()
{
return this.id;
}
/**
* Gets the workbench part used to initialize this instance.
* #return
*/
public final IWorkbenchPart getPart()
{
return this.part;
}
/* (non-Javadoc)
* #see com.ibm.lotuslabs.context.service.document.IDocumentContext#getImageDescriptor()
*/
public final ImageDescriptor getImageDescriptor()
{
return this.icon;
}
/* (non-Javadoc)
* #see com.ibm.lotuslabs.context.service.document.IDocumentContext#getLabel()
*/
public final String getLabel()
{
if (this.label == null && this.part != null)
{
return this.part.getTitle();
}
return this.label;
}
/* (non-Javadoc)
* #see com.ibm.lotuslabs.context.service.document.IDocumentContext#getObject()
*/
public final Object getObject()
{
return this.obj;
}
/* (non-Javadoc)
* #see com.ibm.lotuslabs.context.service.document.IDocumentContext#getProperties()
*/
public final Properties getProperties()
{
return this.properties;
}
/* (non-Javadoc)
* #see com.ibm.lotuslabs.context.service.document.IDocumentContext#getURI()
*/
public final URI getURI()
{
return this.uri;
}
private Properties buildProperties(final IPropertySource source)
{
if (source == null)
{
return null;
}
final IPropertyDescriptor[] descs = source.getPropertyDescriptors();
if (The.Value(null).Is.NullOrEmpty(descs))
{
return null;
}
final Properties prop = new Properties();
for (int i = 0; i < descs.length; i++)
{
final Object id = descs[i].getId();
final String name = descs[i].getDisplayName();
String value = source.getPropertyValue(descs[i].getId()).toString();
if (The.Value(descs[i].getDescription()).Is.Not.Null())
{
value += "|" + source.getPropertyValue(descs[i].getDescription()).toString();
}
if (this.uri == null)
{
if (The.Value("URI").Is.OneOfIgnoreCase(id.toString(), name) ||
The.Value("URL").Is.OneOfIgnoreCase(id.toString(), name))
{
try
{
this.uri = new URI(value);
continue;
}
catch (URISyntaxException e)
{
}
}
}
prop.setProperty(name, value);
}
return prop;
}
}
Sorry, until the document is saved into the backend database, there is no document to get an URI for, as it does not exists anywhere but in memory. It simply does not exists on disk.

Error adding auto-complete component to ICEFaces screen

I am trying to create a pretty straight forward screen that has a text field with auto-complete functionality. I have been following the examples found on the ICEFaces website here. No matter what I try I keep getting this error:
java.lang.ClassCastException: java.lang.String cannot be cast to javax.faces.model.SelectItem
at com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.countSelectOptionsRecursive(MenuRenderer.java:444)
at com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.renderSelect(MenuRenderer.java:370)
at com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.encodeEnd(MenuRenderer.java:119)
at com.icesoft.faces.component.ext.renderkit.MenuRenderer.encodeEnd(MenuRenderer.java:51)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:836)
at com.icesoft.faces.component.util.CustomComponentUtils.renderChild(CustomComponentUtils.java:343)
at com.icesoft.faces.component.util.CustomComponentUtils.renderChildren(CustomComponentUtils.java:325)
at com.icesoft.faces.component.panellayout.PanelLayoutRenderer.encodeChildren(PanelLayoutRenderer.java:75)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:812)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:517)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:522)
at com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:481)
at com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:153)
at org.icefaces.netbeans.rave.web.ui.appbase.faces.ViewHandlerImpl.renderView(ViewHandlerImpl.java:296)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
at com.icesoft.faces.webapp.http.core.JsfLifecycleExecutor.apply(JsfLifecycleExecutor.java:19)
at com.icesoft.faces.context.View$2$1.respond(View.java:48)
at com.icesoft.faces.webapp.http.servlet.GlassFishAdaptingServlet$GlassFishRequestResponse.respondWith(GlassFishAdaptingServlet.java:159)
at com.icesoft.faces.context.View$2.serve(View.java:76)
at com.icesoft.faces.context.View.servePage(View.java:139)
at com.icesoft.faces.webapp.http.core.SingleViewServer.service(SingleViewServer.java:52)
at com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11)
at com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:114)
at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24)
at com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:160)
at com.icesoft.faces.webapp.http.servlet.SessionDispatcher$1.service(SessionDispatcher.java:42)
at com.icesoft.faces.webapp.http.servlet.GlassFishAdaptingServlet.service(GlassFishAdaptingServlet.java:60)
at com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63)
at com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:62)
at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
at com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:153)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:831)
at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:411)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:290)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:271)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:202)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:632)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:577)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:206)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:632)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:577)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:571)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1080)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:150)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:632)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:577)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:571)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1080)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:272)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:637)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:568)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:813)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLReadTask.process(SSLReadTask.java:440)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLReadTask.doTask(SSLReadTask.java:228)
at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
The stack trace never points to any of my code directly so I am having trouble tracking this down. I am sure it is something I am doing wrong. Following the example from the website above for Auto-completes I have a Dictionary class (called AutoCompleteDictionary) and Bean Class (called AutoCompleteBean). The section in the jsp for the component looks like:
<ice:selectInputText id="acModelNumber" rows="10" width="216" style="left: 240px; top: 124px; position: absolute" value="#{autoCompleteBean.selectedStringValue1}" valueChangeListener="#{autoCompleteBean.selectInputValueChanged}">
<f:selectItems id="acModelNumberItems" value="#{autoCompleteBean.stringMatchPossibilities}"/>
</ice:selectInputText>
And AutoCompleteDictionary.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.faces.model.SelectItem;
public class AutoCompleteDictionary {
// initialized flag, only occures once ber deployment.
private static boolean initialized;
// list of Strings
private static ArrayList stringDictionary;
/**
* Creates a new instnace of StringDictionary.
*/
public AutoCompleteDictionary() {
try {
MessageLog.info(this,"AutoCompleteDictionary initialized");
// initialized the bean, load xml database.
synchronized (this) {
init();
}
} catch (Exception e) {
MessageLog.error(this, "Error Initializing AutoCompleteDictionary", e);
}
}
/**
* Comparator utility for sorting Strings.
*/
private static final Comparator LABEL_COMPARATOR = new Comparator() {
// compare method for string entries.
public int compare(Object o1, Object o2) {
SelectItem selectItem1 = (SelectItem) o1;
SelectItem selectItem2 = (SelectItem) o2;
// compare ignoring case, give the user a more automated feel when typing
return selectItem1.getLabel().compareToIgnoreCase(selectItem2.getLabel());
}
};
/**
* Gets the stringDictionary of strings.
*
* #return stringDictionary list in sorted by string name, ascending.
*/
public List getDictionary() {
return stringDictionary;
}
/**
* Generates a short list of cities that match the given searchWord. The
* length of the list is specified by the maxMatches attribute.
*
* #param searchWord string name to search for
* #param maxMatches max number of possibilities to return
* #return list of SelectItem objects which contain potential string names.
*/
public ArrayList generateStringMatches(String searchWord, int maxMatches) {
ArrayList matchList = new ArrayList(maxMatches);
// ensure the autocomplete search word is present
if ((searchWord == null) || (searchWord.trim().length() == 0)) {
return matchList;
}
try {
SelectItem searchItem = new SelectItem("", searchWord);
int insert = Collections.binarySearch(
stringDictionary,
searchItem,
LABEL_COMPARATOR);
// less then zero if we have a partial match
if (insert < 0) {
insert = Math.abs(insert) - 1;
} else {
// If there are duplicates in a list, ensure we start from the first one
if (insert != stringDictionary.size() && LABEL_COMPARATOR.compare(searchItem, stringDictionary.get(insert)) == 0) {
while (insert > 0 && LABEL_COMPARATOR.compare(searchItem, stringDictionary.get(insert - 1)) == 0) {
insert = insert - 1;
}
}
}
for (int i = 0; i < maxMatches; i++) {
// quit the match list creation if the index is larger than
// max entries in the stringDictionary if we have added maxMatches.
if ((insert + i) >= stringDictionary.size() ||
i >= maxMatches) {
break;
}
matchList.add(stringDictionary.get(insert + i));
}
} catch (Throwable e) {
MessageLog.error(this, "Error finding Matches", e);
}
// assign new matchList
return matchList;
}
/**
* Hits the database to load the list of Model Numbers.
*/
private static void init() throws IOException {
if (!initialized) {
initialized = true;
List<String> temp = //get list of strings via a db call;
stringDictionary = new ArrayList(temp.size());
String tmpString;
for (int i = 0, max = temp.size(); i < max; i++) {
tmpString = temp.get(i);
if (tmpString != null && !tmpString.equals("")) {
stringDictionary.add(new SelectItem(tmpString, tmpString));
}
}
temp.clear();
Collections.sort(stringDictionary, LABEL_COMPARATOR);
}
}
}
And AutoCompleteBean.java
import com.icesoft.faces.component.selectinputtext.SelectInputText;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;
public class AutoCompleteBean extends BaseBean {
// string dictionary
private AutoCompleteDictionary stringDictionary;
// list of possible string matches for a given string dictionary lookup
private SelectItemGroup stringMatchPossibilities;
// number of string possibilities to show
private static int stringListLength = 15;
// value associatd with first selectInput Component
private String selectedStringValue1 = "";
// value associatd with first selectInput Component
private String selectedStringValue2 = "";
// selected String information, assigned when user uses mouse or enter key
// to select a String.
private String selectedString;
public AutoCompleteBean() {
selectedString = "";
}
/**
* <p>Called by the selectInputText component at set intervals. By using
* the change event we can can get the newly typed work and do a look up in
* the string dictionary. The list of possible strings calculatd from the string
* dictionary is assigned back to the component for display.</p>
* <p>If the component selected a value then we find the respective string
* information for dispaly purposes.
*
* #param event jsf value change event.
*/
public void selectInputValueChanged(ValueChangeEvent event) {
if (event.getComponent() instanceof SelectInputText) {
// get the number of displayable records from the component
SelectInputText autoComplete =
(SelectInputText) event.getComponent();
// get the new value typed by component user.
String newWord = (String) event.getNewValue();
stringMatchPossibilities = new SelectItemGroup();
stringMatchPossibilities.setSelectItems((SelectItem[])(stringDictionary.generateStringMatches(newWord, stringListLength)).toArray());
// if there is a selected item then find the string object of the
// same name
if (autoComplete.getSelectedItem() != null) {
selectedString = (String) autoComplete.getSelectedItem().getValue();
// fire effect to draw attention
valueChangeEffect.setFired(false);
}
// if there was no selection we still want to see if a proper
// string was typed and update our selectedString instance.
else{
String tmp = getFindStringMatch(newWord);
if (tmp != null){
selectedString = tmp;
// fire effect to draw attention
valueChangeEffect.setFired(false);
}
}
}
}
/**
* Utility method for finding detailed string information from the list of
* possibile strings.
*
* #param stringName string to search on.
* #return found string object if any, null otherwise.
*/
private String getFindStringMatch(String stringName) {
SelectItem[] temp = stringMatchPossibilities.getSelectItems();
if (stringMatchPossibilities != null) {
SelectItem string;
for(int i = 0, max = temp.length; i < max; i++){
string = temp[i];
if (string.getLabel().compareToIgnoreCase(stringName) == 0) {
return (String) string.getValue();
}
}
}
return null;
}
public void setStringDictionary(AutoCompleteDictionary stringDictionary) {
this.stringDictionary = stringDictionary;
}
public SelectItemGroup getStringMatchPossibilities() {
return stringMatchPossibilities;
}
public String getSelectedString() {
return selectedString;
}
public void setSelectedString(String selectedString) {
this.selectedString = selectedString;
}
public String getSelectedStringValue1() {
return selectedStringValue1;
}
public void setSelectedStringValue1(String selectedStringValue1) {
this.selectedStringValue1 = selectedStringValue1;
}
public String getSelectedStringValue2() {
return selectedStringValue2;
}
public void setSelectedStringValue2(String selectedStringValue2) {
this.selectedStringValue2 = selectedStringValue2;
}
public int getStringListLength() {
return stringListLength;
}
}
And what I added to my facesConfig.xml
<managed-bean>
<managed-bean-name>autoCompleteBean</managed-bean-name>
<managed-bean-class>/*the package*/.AutoCompleteBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>autoCompleteDictionary</managed-bean-name>
<managed-bean-class>/*the package*/.AutoCompleteDictionary</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
I know this is a lot of information, but does anyone have any pointers or might see what I am doing wrong?
We do not need read to documentation to predict how this method
public List getCityMatchPossibilities() { ... }
is used here:
<f:selectItems id="AutoCmpTxtItms"
value="#{selectInputText.cityMatchPossibilities}"/>
But your method is not so simple:
public SelectItemGroup getStringMatchPossibilities() { ... }

Categories

Resources