You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@abdera.apache.org by "Rushforth, Peter" <Pe...@NRCan-RNCan.gc.ca> on 2013/02/12 20:47:07 UTC
advice: upgrade or work around?
Hi There,
Thanks for abdera, it is wonderful.
I am developing in an abdera 0.3.0 project (atomserver), and I have come across an issue that is a bit puzzling.
I want to add an 'annotated' link element (to a collection element inside the feed) which describes our api, but the mere addition of this element is very slow, so slow that I am wondering if it is a bug somewhere deep inside that version of abdera.
(I tried the obvious, to upgrade to version 1.1.3 of abdera, but there are a lot of red lines in my ide after that, so it's a bit daunting).
I believe it is my Element getCollectionAPI(RequestContext request) implementation, with its heavy use of ExtensibleElement, which performs badly, but I'm not 100% sure. I know for a fact that my getCollection(RequestContext request) performs badly, based on timings ( 1-10 seconds!).
Can you advise what the best path to take is, please?
Thanks and cheers,
Peter
The code which I'm using to add the link element goes like this:
public org.apache.abdera.model.Collection
getCollection(RequestContext request) {
Abdera abdera = request.getServiceContext().getAbdera();
AtomWorkspace atomWorkspace = this.parentAtomWorkspace;
AtomService atomService = atomWorkspace.getParentAtomService();
URIHandler uriHandler = atomService.getURIHandler();
String workspace = atomWorkspace.getName();
String collName = this.name;
Factory factory = AtomServer.getFactory(abdera);
org.apache.abdera.model.Collection e = factory.newCollection();
TargetType t = atomService.getURIHandler().resolve(request).getType();
try {
// set a relative URI as the href; this assumes xml:base is
// set to the service document
e.setHref("./");
e.setBaseUri(uriHandler.constructURIString(workspace, collName)+"/");
e.setTitle(collName);
// e.addAccepts("");
// does not have the desired effect, which is to place an
// empty accept element in the document, which indicates that a
// feed is read-only: http://tools.ietf.org/html/rfc5023#section-8.3.4
// workaround: use a namespaced extension to accomplish that
e.addExtension(AtomServerConstants.COLLECTION_ACCEPT);
boolean categoriesExist = atomWorkspace.
getAtomCollection(collName).
categoriesExist(workspace, collName);
// admin can setup workspaceBeans.xml to allow
// stand-alone category documents, accessible via the
// href attribute. Whether this is true or not
// is based on the value of the
// defaultProducingInLineCategoriesServiceElement value.
if (categoriesExist) {
Categories categories = e.addCategories();
// when the target of the request is the service document,
// it is up to the administrator as to whether the categories
// are placed in-line or not.
if (t == TargetType.TYPE_SERVICE) {
if (atomWorkspace.getOptions()
.getDefaultProducingInLineCategoriesServiceElement()) {
java.util.Collection<Category> categoryList =
atomWorkspace.getAtomCollection(collName).listCategories(request);
for (Category category : categoryList) {
categories.addCategory(category);
}
}
} else {
// when the target is a collection or the admin has said
// that categories are always referenced, put the URI of
// the categories doc in the categories@href value.
String chref = atomService.getURIHandler()
.constructURIString(workspace, collName) + "/$categories/";
categories.setHref(chref);
}
} else {
e.addCategories().setFixed(false);
}
Element api = getCollectionAPI(request);
if (api != null) {
e.addExtension(getCollectionAPI(request));
}
} catch (IRISyntaxException ie) {
throw new BadRequestException(ie);
}
return e;
}
private Element getCollectionAPI(RequestContext request) {
Abdera abdera = request.getServiceContext().getAbdera();
AtomWorkspace atomWorkspace = this.parentAtomWorkspace;
AtomService atomService = atomWorkspace.getParentAtomService();
URIHandler uriHandler = atomService.getURIHandler();
String workspace = atomWorkspace.getName();
String collName = this.name;
Factory factory = AtomServer.getFactory(abdera);
ExtensibleElement api =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS,"link"));
api.setAttributeValue("rel","api");
api.setAttributeValue("type", "{+mediaType}");
api.setAttributeValue("href",".");
api.setAttributeValue("tref", "{+categoryQuery}?{+uriQuery}");
ExtensibleElement mediaType =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "mediaType"));
for (String mt : this.getNegotiableMimeTypes()) {
ExtensibleElement mvalue =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
mvalue.setText(mt);
if (mt.equalsIgnoreCase(this.defaultMediaType.getMediaType()))
mvalue.setAttributeValue("default", "true");
mediaType.addExtension(mvalue);
}
api.addExtension(mediaType);
ExtensibleElement categoryQuery =
factory.newExtensionElement(
new QName( AtomServerConstants.ATOM_NS, "categoryQuery"));
categoryQuery.setAttributeValue("tref", "{+catPathSep}/{+categories}");
ExtensibleElement catpathsep =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "catPathSep"));
Element cpsvalue = factory.newElement(new QName(AtomServerConstants.ATOM_NS,"value"));
cpsvalue.setText("-");
catpathsep.addExtension(cpsvalue);
categoryQuery.addExtension(catpathsep);
ExtensibleElement categories =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "categories"));
Element catpattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
catpattern.setText("(\\([.:a-zA-Z0-9]*\\)[a-zA-Z0-9]+/|[aA][nN][dD]/|[oO][rR]/)*");
categories.addExtension(catpattern);
ExtensibleElement link =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS,"link"));
link.setAttributeValue("rel","suggestions");
link.setAttributeValue("type","application/vnd.nrcan.suggestions+{subtype}");
link.setAttributeValue("href", ".");
link.setAttributeValue("tref", "{?q}");
link.setBaseUri("./$categories/");
ExtensibleElement cat_sugg_link_subtype =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "subtype"));
cat_sugg_link_subtype.addSimpleExtension(new QName(AtomServerConstants.ATOM_NS, "value"), "json");
cat_sugg_link_subtype.addSimpleExtension(new QName(AtomServerConstants.ATOM_NS, "value"), "xml");
link.addExtension(cat_sugg_link_subtype);
ExtensibleElement cat_sugg_link_q =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "q"));
cat_sugg_link_q.addSimpleExtension(new QName(AtomServerConstants.ATOM_NS, "pattern"), "[ \\+.:\\-a-zA-Z0-9]*");
link.addExtension(cat_sugg_link_q);
categories.addExtension(link);
categoryQuery.addExtension(categories);
api.addExtension(categoryQuery);
ExtensibleElement uriQuery =
factory.newExtensionElement(
new QName( AtomServerConstants.ATOM_NS, "uriQuery"));
uriQuery.setAttributeValue("tref", "{+q}{bbox}&updated-min={updatedMin}&updated-max={updatedMax}&max-results={maxResults}&entry-type={entryType}{&callback}&sort-field={sortField}{&alt}");
ExtensibleElement q =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "q"));
Element qpattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
qpattern.setText("[ \\+.:\\-a-zA-Z0-9]*");
q.addExtension(qpattern);
ExtensibleElement q_sugg_link =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "link"));
q_sugg_link.setAttributeValue("rel", "suggestions");
q_sugg_link.setAttributeValue("type", "application/vnd.nrcan.suggestions+{subtype}");
q_sugg_link.setAttributeValue("href", ".");
q_sugg_link.setAttributeValue("tref", "{?q}");
ExtensibleElement subtype =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "subtype"));
ExtensibleElement valuexml =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
valuexml.setText("xml");
ExtensibleElement valuejson =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
valuejson.setText("json");
subtype.addExtension(valuexml);
subtype.addExtension(valuejson);
q_sugg_link.addExtension(subtype);
ExtensibleElement q_sugg_link_q =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "q"));
q_sugg_link_q.addExtension((Element)qpattern.clone());
q_sugg_link.addExtension(q_sugg_link_q);
q.addExtension(q_sugg_link);
uriQuery.addExtension(q);
ExtensibleElement bbox =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "bbox"));
bbox.setAttributeValue("format","west,south,east,north");
bbox.setAttributeValue("units","decimal degrees");
Element bboxpattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
bboxpattern.setText("-[\\d]{1,3}[\\.][\\d]{1,},-[\\d]{1,2}[\\.][\\d]{1,},[\\d]{1,3}[\\.][\\d]{1,},[\\d]{1,2}[\\.][\\d]{1,}");
bbox.addExtension(bboxpattern);
ExtensibleElement bbox_sugg_link =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "link"));
//http://geogratis.gc.ca/loc/en/loc?q=false&match=leading
bbox_sugg_link.setAttributeValue("rel", "suggestions");
bbox_sugg_link.setAttributeValue("type", "application/vnd.nrcan.suggestions+{subtype}");
bbox_sugg_link.setAttributeValue("href", ".");
bbox_sugg_link.setAttributeValue("tref", "?match=leading&{q}");
bbox_sugg_link.setBaseUri("http://geogratis.gc.ca/loc/en/loc/");
bbox_sugg_link.addExtension((Element)subtype.clone());
ExtensibleElement bbox_sugg_link_q =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "q"));
Element bbox_sugg_link_qpattern =
factory.newElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
bbox_sugg_link_qpattern.setText("[ \\+.:\\-a-zA-Z0-9]*");
bbox_sugg_link_q.addExtension(bbox_sugg_link_qpattern);
bbox_sugg_link.addExtension(bbox_sugg_link_q);
bbox.addExtension(bbox_sugg_link);
String date_regex = "[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))(T{0,1}(([0-1][0-9])|([2][0-3])):[0-5][0-9]:([0-5][0-9])(\\.[\\d]{0,2}){0,1})(Z|([\\-+]([0-1][0-9]|2[0-3]))(:[0-5][0-9])?)";
uriQuery.addExtension(bbox);
ExtensibleElement updated_min =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "updatedMin"));
Element updated_minpattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
// the regex is rough and may allow more than it should...
updated_minpattern.setText(date_regex);
updated_min.addExtension(updated_minpattern);
uriQuery.addExtension(updated_min);
ExtensibleElement updated_max =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "updatedMax"));
Element updated_maxpattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
updated_maxpattern.setText(date_regex);
updated_max.addExtension(updated_maxpattern);
uriQuery.addExtension(updated_max);
ExtensibleElement max_results =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "maxResults"));
Element max_resultspattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
int maxfull = atomWorkspace.getOptions().getMaxFullMaxResults();
int maxlink = atomWorkspace.getOptions().getMaxLinkMaxResults();
int max = maxlink > maxfull ? maxlink : maxfull;
// the domain of max-results depends on the value of entry-type, but
// for the sake of simplicity, we'll put out a regex which covers the
// maximum possible range
max_resultspattern.setText(NumericRangeRegexGenerator.rangeRegex(0, max));
max_results.addExtension(max_resultspattern);
uriQuery.addExtension(max_results);
ExtensibleElement entry_type =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "entryType"));
for (EntryType et : EntryType.values()) {
ExtensibleElement entry_type_value =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
entry_type_value.setText(et.name());
if (et == EntryType.link)
entry_type_value.setAttributeValue("default", "true");
entry_type.addExtension(entry_type_value);
}
uriQuery.addExtension(entry_type);
ExtensibleElement callback =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "callback"));
Element callbackpattern =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "pattern"));
callbackpattern.setText("[a-zA-Z0-9]{1,64}");
callback.addExtension(callbackpattern);
uriQuery.addExtension(callback);
ExtensibleElement locale =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "locale"));
Element locale_en_CA =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
locale_en_CA.setText("en_CA");
Element locale_fr_CA =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
locale_fr_CA.setText("fr_CA");
// set the default value of locale to correspond with the en/fr
// servlet mapping convention. This can be overridden by the client
// inserting a locale parameter.
if (uriHandler.getServletMapping().equalsIgnoreCase("fr"))
locale_fr_CA.setAttributeValue("default", "true");
else
locale_en_CA.setAttributeValue("default", "true");
locale.addExtension(locale_en_CA);
locale.addExtension(locale_fr_CA);
uriQuery.addExtension(locale);
ExtensibleElement sort =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "sortField"));
Element sort_value =
factory.newElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
sort_value.setText(SortType.spatial.name());
Element default_sort_value = (Element)sort_value.clone();
default_sort_value.setText(SortType.edited.name());
default_sort_value.setAttributeValue("default", "true");
sort.addExtension(default_sort_value);
sort.addExtension(sort_value);
uriQuery.addExtension(sort);
// alt will have a more elaborate contents, in which the media type and
// the 'file extension' are associated. The media type is intended as
// legitimate values of the Accept: protocol header, whereas the file
// extension is intended to be supplied via the alt parameter to identify
// a resource which is a view onto a single format among many possible
// formats negotiable from the un-parameterized resource. The header
// takes priority over the URI parameter (? - verify before putting this
// in api documentation.
ExtensibleElement alt =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "alt"));
for (String ext:this.getNegotiableFormatExtensions()) {
ExtensibleElement mvalue =
factory.newExtensionElement(
new QName(AtomServerConstants.ATOM_NS, "value"));
mvalue.setText(ext);
if (ext.equalsIgnoreCase(this.defaultMediaType.getExtension()))
mvalue.setAttributeValue("default", "true");
alt.addExtension(mvalue);
}
uriQuery.addExtension(alt);
api.addExtension(uriQuery);
return api;
}