I am working on a news app. I have 5 categories of news sections. Each tab or section, calls to a different URL and has a separate table in the local database, hence a different URI(using a ContentProvider), when retrieving local data.
I have one AsyncTask that services all the requests. It determines which url or uri to call based on the instance of the class passed to it. All the tabs/sections/fragments/classes inherit from a common base class..
Now, I will like to change the AsyncTask to an IntentService, so I can use the AlarmManager class. I have noticed that, there seems to be no easy way of passing an object via intents.
I need a way of determining which particular class of the 5 classes called the IntentService, so the appropriate action is taken.
This class is called when the instance of the class is to be determined:
public class GetURL {
public static URL GetURL(TabsSuperClass tabs)
{
URL url = null;
try {
if(tabs instanceof CultureFrag)
{
final String baseUri = "http://content.guardianapis.com/search?";
Uri uriBuilder = Uri.parse(baseUri)
.buildUpon()
.appendQueryParameter("section", "culture|local|music|books|society")
.appendQueryParameter("order-by", "newest")
.appendQueryParameter("use-date", "published")
.appendQueryParameter("show-fields", "trailText,thumbnail")
.appendQueryParameter("page", String.valueOf(TabsSuperClass.pageSize))
.appendQueryParameter("page-size", "10")
.appendQueryParameter("api-key", "Test-Key")
.build();
url = new URL(uriBuilder.toString());
}
else if(tabs instanceof LifeStyleFrag)
{
final String baseUri = "http://content.guardianapis.com/search?";
Uri uriBuilder = Uri.parse(baseUri)
.buildUpon()
.appendQueryParameter("section", "lifeandstyle|education|fashion|help")
.appendQueryParameter("order-by", "newest")
.appendQueryParameter("use-date", "published")
.appendQueryParameter("show-fields", "trailText,thumbnail")
.appendQueryParameter("page", String.valueOf(LifeStyleFrag.pageSize))
.appendQueryParameter("page-size", "10")
.appendQueryParameter("api-key", "Test-Key")
.build();
url = new URL(uriBuilder.toString());
}
else if(tabs instanceof ScienceFrag)
{
final String baseUri = "http://content.guardianapis.com/search?";
Uri uriBuilder = Uri.parse(baseUri)
.buildUpon()
.appendQueryParameter("section", "science|environment|technology|business")
.appendQueryParameter("order-by", "newest")
.appendQueryParameter("use-date", "published")
.appendQueryParameter("show-fields", "trailText,thumbnail")
.appendQueryParameter("page", String.valueOf(ScienceFrag.pageSize))
.appendQueryParameter("page-size", "10")
.appendQueryParameter("api-key", "Test-Key")
.build();
url = new URL(uriBuilder.toString());
}
else if(tabs instanceof SportFrag)
{
final String baseUri = "http://content.guardianapis.com/search?";
Uri uriBuilder = Uri.parse(baseUri)
.buildUpon()
.appendQueryParameter("section", "sport|football")
.appendQueryParameter("order-by", "newest")
.appendQueryParameter("use-date", "published")
.appendQueryParameter("show-fields", "trailText,thumbnail")
.appendQueryParameter("page", String.valueOf(SportFrag.pageSize))
.appendQueryParameter("page-size", "10")
.appendQueryParameter("api-key", "Test-Key")
.build();
url = new URL(uriBuilder.toString());
}
else if(tabs instanceof WorldFrag)
{
final String baseUri = "http://content.guardianapis.com/search?";
Uri uriBuilder = Uri.parse(baseUri)
.buildUpon()
.appendQueryParameter("section", "world|opinion|media|us-news|australia-news|uk-news")
.appendQueryParameter("order-by", "newest")
.appendQueryParameter("use-date", "published")
.appendQueryParameter("show-fields", "trailText,thumbnail")
.appendQueryParameter("page", String.valueOf(WorldFrag.pageSize))
.appendQueryParameter("page-size", "10")
.appendQueryParameter("api-key", "Test-Key")
.build();
url = new URL(uriBuilder.toString());
}
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
return url;
}
public static Uri GetContentUri(TabsSuperClass tabs)
{
Uri uri = null;
if(tabs instanceof CultureFrag)
{
return NewsContract.CONTENT_URI_CULTURE;
}
else if(tabs instanceof LifeStyleFrag)
{
return NewsContract.CONTENT_URI_LIFESTYLE;
}
else if(tabs instanceof ScienceFrag)
{
return NewsContract.CONTENT_URI_SCIENCE;
}
else if(tabs instanceof SportFrag)
{
return NewsContract.CONTENT_URI_SPORT;
}
else if(tabs instanceof WorldFrag)
{
return NewsContract.CONTENT_URI_WORLD;
}
return uri;
}
}
urlConnection = (HttpURLConnection)GetURL.GetURL(_fragment).openConnection();
An instance where this class is called is here, when I am inserting data into the table of the class which called
private void InsertIntoTable(List<NewsFacade> data) {
for (NewsFacade facade :
data) {
ContentValues values = new ContentValues();
values.put(NewsContract.DataContract.COLUMN_NAME_DATE, facade.getDate());
values.put(NewsContract.DataContract.COLUMN_NAME_CONTENT, facade.getText());
values.put(NewsContract.DataContract.COLUMN_NAME_TAG, facade.getTag());
byte[] image = EncodeImage(facade.getThumb());
values.put(NewsContract.DataContract.COLUMN_NAME_THUMB, image);
values.put(NewsContract.DataContract.COLUMN_NAME_TITLE, facade.getTitle());
values.put(NewsContract.DataContract.COLUMN_NAME_WEBADDRESS, facade.getWebAddress());
_fragment.mResolver.insert(GetURL.GetContentUri(_fragment), values);
}
}
I need a way of determining which particular class of the 5 classes called the IntentService, so the appropriate action is taken.
Put an extra on the Intent that you pass to startActivity() that indicates what the IntentService should do. You get a copy of that Intent in onHandleIntent() in the IntentService, so you can retrieve the extra and take appropriate steps based upon its value.
At the top of the activity I add:-
private final static String THIS_ACTIVITY = "AddProductToShopActivity";
for the intent I add:
intent.putExtra("CALLER", THIS_ACTIVITY);
In the started activity :-
final String caller = getIntent().getStringExtra("Caller");
Related
I have immutable objects as follows.
#Getter
#Builder
class MainDetail {
// 5 other String fields
private Data data;
}
#Getter
#Builder
class ImageUrl {
private final String dataOne; // looking to change these 2 values
private final String dataTwo; // if rest call returns null for these.
}
Information to fill these up is fetched from a rest call, working fine as follows.
List<MainDetail> featureBenefits = // value from a rest response
I wish to switch out the dataOne and dataTwo values in here if it is null for each MainDetail Object.
I can't just use a set method to do this cos it is immutable.
I end up with the following verbose way of doing it where I need to do multiple variations of the check to swap values.
I can't just check one at a time and switch cos Object becomes immutable. Can't add another if the second one is null too after that.
Is there a way to do this more elegantly, possibly via streams? Appreciate any help. Thanks.
List<MainDetail> mainDetails = new ArrayList<>();
for (MainDetail mainDetail : featureBenefits) {
if (mainDetail.getImageUrl().getDataOne() == null && mainDetail.getImageUrl().getdataTwo() == null) {
ImageUrl imageUrl = ImageUrl.builder()
.dataOne("default1")
.dataTwo("default12")
.build();
MainDetail detail = MainDetail.builder()
.imageUrl(imageUrl)
.build();
mainDetails.add(detail);
}
else if (mainDetail.getImageUrl().getdataOne() == null) {
ImageUrl imageUrl = ImageUrl.builder()
.dataOne("default1")
.build();
MainDetail detail = MainDetail.builder()
.imageUrl(imageUrl)
.build();
mainDetails.add(detail);
}
else if (mainDetail.getImageUrl().getDataTwo() == null) {
ImageUrl imageUrl = ImageUrl.builder()
.dataTwo("default2")
.build();
MainDetail detail = MainDetail.builder()
.imageUrl(imageUrl)
.build();
mainDetails.add(detail);
}
}
What about this one:
List<MainDetail> featureBenefits = Collections.emptyList();
List<MainDetail> mainDetails = new ArrayList<>();
for (MainDetail mainDetail : featureBenefits) {
ImageUrl imageUrl = mainDetail.getImageUrl();
mainDetails.add(MainDetail.builder()
.imageUrl(ImageUrl.builder()
.dataOne(Optional.ofNullable(imageUrl.getDataOne()).orElse("default1"))
.dataTwo(Optional.ofNullable(imageUrl.getDataTwo()).orElse("default2"))
.build())
.build());
}
If you are not limited to sticking with standard builders then you could add your own methods for providing default values:
class ImageUrl {
private final String dataOne; // looking to change these 2 values
private final String dataTwo; // if rest call returns null for these.
public ImageUrl withDefaultDataOne(String value) {
return dataOne == null ? new ImageUrl(value, dataTwo) : this;
}
public ImageUrl withDefaultDataTwo(String value) {
return dataTwo == null ? new ImageUrl(dataOne, value) : this;
}
}
Then your translation code becomes:
for (MainDetail mainDetail : featureBenefits) {
ImageUrl imageUrl = mainDetail.getImageUrl()
.withDefaultDataOne("default1")
.withDefaultDataTwo("default2");
mainDetails.add(MainDetail.builder().imageUrl(imageUrl).build());
}
I have bellow url :
http://www.example.com/api/Video/GetListMusicRelated/0/0/null/105358/0/0/10/null/null
This section is Fixed and unchangeable:
http://www.example.com/api/Video/GetListMusicRelated/
I set parameter to this url like bellow :
http://www.example.com/api/Video/GetListMusicRelated/25/60/jim/105358/20/1/5/null/null
OR :
http://www.example.com/api/Video/GetListMusicRelated/0/0/null/105358,5875,85547/0/0/10/null/null
How I can write for this url a url builder ?
If you want to create an UrlBuilder using the builder pattern, it could be done like this:
public class UrlBuilder {
private final String root;
private int myParam1;
private String myParam2;
public UrlBuilder(final String root) {
this.root = root;
}
public UrlBuilder myParam1(int myParam1) {
this.myParam1 = myParam1;
return this;
}
public UrlBuilder myParam2(String myParam2) {
this.myParam2 = myParam2;
return this;
}
public URL build() throws MalformedURLException {
return new URL(
String.format("%s/%d/%s", root, myParam1, myParam2)
);
}
}
Then you will be able to create your URL as next
URL url = new UrlBuilder("http://www.example.com/api/Video/GetListMusicRelated")
.myParam1(25)
.myParam2("jim")
.build();
NB: This only shows the idea, so I used fake parameter's name and incorrect number of parameters, please note that you are supposed to have 6 parameters and set the proper names.
try this...
URL domain = new URL("http://example.com");
URL url = new URL(domain + "/abcd/abcd");
The Post object has a property getPicture(). This contains an url to a very small (130 × 130) image.
How to get the big picture of a Facebook post?
Sample url:
https://scontent.xx.fbcdn.net/v/t1.0-0/s130x130/13173717_10209376327474891_7842199861010585961_n.jpg?oh=d244df2db666e1d3be73cb7b76060337&oe=57A64C44
It does not help to replace the s130x130 in the url because that won't work in the new Graph API.
I tried to use graphApi.mediaOperations() but I don't see a method that accepts a postId. There is graphApi.mediaOperations().getPhotos(objectID) but this objectID has to be an AlbumID or UserID according to the documentation and this method throws an exception:
org.springframework.social.UncategorizedApiException: (#100) Tried accessing nonexisting field (photos) on node type (Photo)
Edit: I found something that works:
byte[] photo = graphApi.mediaOperations().getAlbumImage(post.getObjectId(), ImageType.NORMAL);
But now I get a byte[] instead of an url so now I have to store the image somewhere :(
i didn't get any direct method to fetch full_picture of Facebook post using Spring Social framework. I used Facebook's graph API to get full picture. I am adding code for references only. you need to be customize as per you need.
FacebookTemplate facebook = new FacebookTemplate("<fb token>");
String[] ALL_POST_FIELDS = { "id", "actions", "admin_creator", "application", "caption", "created_time", "description", "from", "icon",
"is_hidden", "is_published", "link", "message", "message_tags", "name", "object_id", "picture", "full_picture", "place", "privacy",
"properties", "source", "status_type", "story", "to", "type", "updated_time", "with_tags", "shares", "likes.limit(1).summary(true)" };
URIBuilder uriBuilder = URIBuilder.fromUri(facebook.getBaseGraphApiUrl() + request.getAccountId() + "/posts");
uriBuilder = uriBuilder.queryParam("limit", String.valueOf(request.getRecordCount()));
uriBuilder.queryParam("fields", org.springframework.util.StringUtils.arrayToCommaDelimitedString(ALL_POST_FIELDS));
URI uri = uriBuilder.build();
LOGGER.info("facebook URL :{} ", uri);
JsonNode jsonNode = (JsonNode) facebook.getRestTemplate().getForObject(uri, JsonNode.class);
LOGGER.debug("facebook URL :{}, response: {} ", uri, jsonNode);
// you can cast jsonnode as required into your format or below line can be used to cast into PagedList<Post> format
PagedList<Post> posts = new DeserializingPosts().deserializeList(jsonNode, null, Post.class, true);
Then jsonNode code be cast into your required format. or you can also cast it to PagedList<Post> using below DeserializingPosts class.
#Component
public class DeserializingPosts extends AbstractOAuth2ApiBinding {
private ObjectMapper objectMapper = new ObjectMapper();
private static final Logger LOGGER = Logger.getLogger(DeserializingPosts.class);
public <T> PagedList<T> deserializeList(JsonNode jsonNode, String postType, Class<T> type, boolean accountFlag) {
JsonNode dataNode = jsonNode.get("data");
return deserializeList(dataNode, postType, type);
}
public <T> PagedList<T> deserializeList(JsonNode jsonNode, String postType, Class<T> type) {
List posts = new ArrayList();
for (Iterator iterator = jsonNode.iterator(); iterator.hasNext();) {
posts.add(deserializePost(postType, type, (ObjectNode) iterator.next()));
}
if (jsonNode.has("paging")) {
JsonNode pagingNode = jsonNode.get("paging");
PagingParameters previousPage = PagedListUtils.getPagedListParameters(pagingNode, "previous");
PagingParameters nextPage = PagedListUtils.getPagedListParameters(pagingNode, "next");
return new PagedList(posts, previousPage, nextPage);
}
return new PagedList(posts, null, null);
}
public <T> T deserializePost(String postType, Class<T> type, ObjectNode node) {
try {
if (postType == null) {
postType = determinePostType(node);
}
node.put("postType", postType);
node.put("type", postType);
MappingJackson2HttpMessageConverter converter = super.getJsonMessageConverter();
this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new FacebookModule());
converter.setObjectMapper(this.objectMapper);
return this.objectMapper.reader(type).readValue(node.toString());
} catch (IOException shouldntHappen) {
throw new UncategorizedApiException("facebook", "Error deserializing " + postType + " post" + shouldntHappen.getMessage(),
shouldntHappen);
}
}
private String determinePostType(ObjectNode node) {
if (node.has("type")) {
try {
String type = node.get("type").textValue();
Post.PostType.valueOf(type.toUpperCase());
return type;
} catch (IllegalArgumentException e) {
LOGGER.error("Error occured while determining post type: " + e.getMessage(), e);
return "post";
}
}
return "post";
}
}
use ImageType.LARGE instead of ImageType.NORMAL
it returns CustomMultipartFile
I'd like to append key-value pair as a query parameter to an existing URL. While I could do this by checking for the existence of whether the URL has a query part or a fragment part and doing the append by jumping though a bunch of if-clauses but I was wondering if there was clean way if doing this through the Apache Commons libraries or something equivalent.
http://example.com would be http://example.com?name=John
http://example.com#fragment would be http://example.com?name=John#fragment
http://example.com?email=john.doe#email.com would be http://example.com?email=john.doe#email.com&name=John
http://example.com?email=john.doe#email.com#fragment would be http://example.com?email=john.doe#email.com&name=John#fragment
I've run this scenario many times before and I'd like to do this without breaking the URL in any way.
There are plenty of libraries that can help you with URI building (don't reinvent the wheel). Here are three to get you started:
Java EE 7
import javax.ws.rs.core.UriBuilder;
...
return UriBuilder.fromUri(url).queryParam(key, value).build();
org.apache.httpcomponents:httpclient:4.5.2
import org.apache.http.client.utils.URIBuilder;
...
return new URIBuilder(url).addParameter(key, value).build();
org.springframework:spring-web:4.2.5.RELEASE
import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();
See also: GIST > URI Builder Tests
This can be done by using the java.net.URI class to construct a new instance using the parts from an existing one, this should ensure it conforms to URI syntax.
The query part will either be null or an existing string, so you can decide to append another parameter with & or start a new query.
public class StackOverflow26177749 {
public static URI appendUri(String uri, String appendQuery) throws URISyntaxException {
URI oldUri = new URI(uri);
String newQuery = oldUri.getQuery();
if (newQuery == null) {
newQuery = appendQuery;
} else {
newQuery += "&" + appendQuery;
}
return new URI(oldUri.getScheme(), oldUri.getAuthority(),
oldUri.getPath(), newQuery, oldUri.getFragment());
}
public static void main(String[] args) throws Exception {
System.out.println(appendUri("http://example.com", "name=John"));
System.out.println(appendUri("http://example.com#fragment", "name=John"));
System.out.println(appendUri("http://example.com?email=john.doe#email.com", "name=John"));
System.out.println(appendUri("http://example.com?email=john.doe#email.com#fragment", "name=John"));
}
}
Shorter alternative
public static URI appendUri(String uri, String appendQuery) throws URISyntaxException {
URI oldUri = new URI(uri);
return new URI(oldUri.getScheme(), oldUri.getAuthority(), oldUri.getPath(),
oldUri.getQuery() == null ? appendQuery : oldUri.getQuery() + "&" + appendQuery, oldUri.getFragment());
}
Output
http://example.com?name=John
http://example.com?name=John#fragment
http://example.com?email=john.doe#email.com&name=John
http://example.com?email=john.doe#email.com&name=John#fragment
For android, Use:
https://developer.android.com/reference/android/net/Uri#buildUpon()
URI oldUri = new URI(uri);
Uri.Builder builder = oldUri.buildUpon();
builder.appendQueryParameter("newParameter", "dummyvalue");
Uri newUri = builder.build();
Use the URI class.
Create a new URI with your existing String to "break it up" to parts, and instantiate another one to assemble the modified url:
URI u = new URI("http://example.com?email=john#email.com&name=John#fragment");
// Modify the query: append your new parameter
StringBuilder sb = new StringBuilder(u.getQuery() == null ? "" : u.getQuery());
if (sb.length() > 0)
sb.append('&');
sb.append(URLEncoder.encode("paramName", "UTF-8"));
sb.append('=');
sb.append(URLEncoder.encode("paramValue", "UTF-8"));
// Build the new url with the modified query:
URI u2 = new URI(u.getScheme(), u.getAuthority(), u.getPath(),
sb.toString(), u.getFragment());
I suggest an improvement of the Adam's answer accepting HashMap as parameter
/**
* Append parameters to given url
* #param url
* #param parameters
* #return new String url with given parameters
* #throws URISyntaxException
*/
public static String appendToUrl(String url, HashMap<String, String> parameters) throws URISyntaxException
{
URI uri = new URI(url);
String query = uri.getQuery();
StringBuilder builder = new StringBuilder();
if (query != null)
builder.append(query);
for (Map.Entry<String, String> entry: parameters.entrySet())
{
String keyValueParam = entry.getKey() + "=" + entry.getValue();
if (!builder.toString().isEmpty())
builder.append("&");
builder.append(keyValueParam);
}
URI newUri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), builder.toString(), uri.getFragment());
return newUri.toString();
}
Use this function to append a new parameter to your existing URI
private Uri appendUriParameter(Uri uri, String key, String newValue) {
final Set<String> params = uri.getQueryParameterNames();
final Uri.Builder newUri = uri.buildUpon().clearQuery();
for (String param : params) {
newUri.appendQueryParameter(param, uri.getQueryParameter(param));
}
newUri.appendQueryParameter(key, newValue);
return newUri.build();
}
Kotlin & clean, so you don't have to refactor before code review:
private fun addQueryParameters(url: String?): String? {
val uri = URI(url)
val queryParams = StringBuilder(uri.query.orEmpty())
if (queryParams.isNotEmpty())
queryParams.append('&')
queryParams.append(URLEncoder.encode("$QUERY_PARAM=$param", Xml.Encoding.UTF_8.name))
return URI(uri.scheme, uri.authority, uri.path, queryParams.toString(), uri.fragment).toString()
}
An update to Adam's answer considering tryp's answer too. Don't have to instantiate a String in the loop.
public static URI appendUri(String uri, Map<String, String> parameters) throws URISyntaxException {
URI oldUri = new URI(uri);
StringBuilder queries = new StringBuilder();
for(Map.Entry<String, String> query: parameters.entrySet()) {
queries.append( "&" + query.getKey()+"="+query.getValue());
}
String newQuery = oldUri.getQuery();
if (newQuery == null) {
newQuery = queries.substring(1);
} else {
newQuery += queries.toString();
}
URI newUri = new URI(oldUri.getScheme(), oldUri.getAuthority(),
oldUri.getPath(), newQuery, oldUri.getFragment());
return newUri;
}
I get the following problem when trying to display a list of items. For each item, I have to display an image which is dynamically loaded via a Wicket WebResource. The items are loaded step by step — 50 at a time — upon user scrolling, using an Ajax scroll.
[ERROR] 2011-04-19 09:58:18,000 btpool0-1 org.apache.wicket.RequestCycle.logRuntimeException (host=, request=, site=):
org.apache.wicket.WicketRuntimeException: component documentList:scroller:batchElem:666:content:item:3:batchItemContent:linkToPreview:imageThumbnail not found on page com.webapp.document.pages.DocumentListPage[id = 1]
listener interface = [RequestListenerInterface name=IResourceListener, method=public abstract void org.apache.wicket.IResourceListener.onResourceRequested()]
org.apache.wicket.protocol.http.request.InvalidUrlException: org.apache.wicket.WicketRuntimeException: component documentList:scroller:batchElem:666:content:item:3:batchItemContent:linkToPreview:imageThumbnail
not found on page com.webapp.document.pages.DocumentListPage[id = 1] listener interface = [RequestListenerInterface name=IResourceListener, method=public abstract void org.apache.wicket.IResourceListener.onResourceRequested()]
at org.apache.wicket.protocol.http.WebRequestCycleProcessor.resolve(WebRequestCycleProcessor.java:262)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1310)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1428)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:479)
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByGuice$$51619816.CGLIB$doGet$6()
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByGuice$$51619816$$FastClassByGuice$$6d42bf5d.invoke()
at com.google.inject.internal.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:64)
at com.freiheit.monitoring.PerformanceMonitoringMethodInterceptor.invoke(PerformanceMonitoringMethodInterceptor.java:115)
at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:64)
at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:44)
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByGuice$$51619816.doGet()
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:312)
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByGuice$$51619816.CGLIB$doFilter$4()
How can this problem be solved?
Here is the part of the code responsible for adding the image:
previewLink.add(createThumbnailSmall("imageThumbnail", documentModel));
in
createThumbnailSmall(final String id, final IModel<BaseDocument> documentModel) {
// thumbnailResource is an object that contains the path of the image
if (thumbnailResource != null) {
final WebResource resource = getWebResource(thumbnailResource);
final Image image = new Image(id, resource);
return image;
}
return new InvisibleContainer(id);
}
WebResource getWebResource(final DocumentResource documentResource) {
return new WebResource() {
private static final long serialVersionUID = 1L;
#Override
public IResourceStream getResourceStream() {
return new BaseStreamResource(documentResource);
}
};
}
where BaseStreamResource is the following:
public class BaseStreamResource extends AbstractResourceStream {
private InputStream _fileInputStream = null;
private DocumentResource _resource = null;
public BaseStreamResource(final DocumentResource documentResource) {
_resource = documentResource;
}
#Override
public InputStream getInputStream() throws ResourceStreamNotFoundException {
if (_fileInputStream == null) {
try {
if (_resource == null) {
throw new ResourceStreamNotFoundException("Resource was null");
}
_fileInputStream = _resource.getFileInputStream();
} catch (final ResourceNotAvailableException ex) {
throw new ResourceStreamNotFoundException(ex);
}
}
return _fileInputStream;
}
In HTML:
<a wicket:id="linkToPreview" href="#">
<img wicket:id="imageThumbnail" alt="Attachment"></img></a>
The code added hasn't really added any clues for me, but maybe I can help narrow it down a bit anyway.
The stacktrace includes a reference to com.webapp.document.pages.DocumentListPage, which is likely calling some of the code you've posted. The error indicates a bad url, so debugging into that class, adding debug prints, and looking at the values of any field containing a url might be worthwhile.
It might even help to modify the code in DocumentListPage (maybe temporarily for debugging) to catch org.apache.wicket.protocol.http.request.InvalidUrlException and adding debugging prints specifically when the exception is caught.
This isn't really an answer, but it's too big for a comment, and maybe it'll help you get closer to an answer.
The following solution solved the problem:
- extend WebResource class
- add extended class as a resource to application shared resources
Ex:
public class MyWebResource extends WebResource {
final ValueMap map = new ValueMap();
#Override
public IResourceStream getResourceStream() {
String fileName = getFileName();
File file = new File(basePath, fileName);
if (!file.exists()) {
LOG.error("File does not exist: " + file);
throw new IllegalStateException("File does not exist: " + file);
}
return new FileResourceStream(file);
}
public final void addResource() {
Application.get().getSharedResources().add(getClass().getName(), this);
}
protected String getFileName() {
return getParameters().getString("id");
}
public final String urlFor(final String fileName) {
final ResourceReference resourceReference = new ResourceReference(getClass().getName());
final String encodedValue = WicketURLEncoder.QUERY_INSTANCE.encode(fileName);
map.add("id", encodedValue);
final CharSequence result = RequestCycle.get().urlFor(resourceReference, map);
if (result == null) {
throw new IllegalStateException("The resource was not added! "
+ "In your Application class add the following line:"
+ "MyConcreteResource.INSTANCE.addResource()");
}
String absoluteUrl = RequestUtils.toAbsolutePath(result.toString());
return absoluteUrl;
}
}
In Application class, in init(), I have added MyWebResource to shared resources:
public void init() {
...
new MyWebResource().addResource();
...
}