/*
* Copyright 2009-2013 Hippo B.V. (http://www.onehippo.com)
* Copyright 2012-2013 Tirasa.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onehippo.taxonomy.plugin.model;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import net.tirasa.hct.taxonomy.frontend.HCTTaxonomyNodeTypes;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.wicket.model.IModel;
import org.hippoecm.frontend.i18n.model.NodeTranslator;
import org.hippoecm.frontend.model.JcrNodeModel;
import org.hippoecm.repository.api.HippoNodeType;
import org.hippoecm.repository.api.NodeNameCodec;
import org.onehippo.taxonomy.api.Category;
import org.onehippo.taxonomy.api.CategoryInfo;
import org.onehippo.taxonomy.api.TaxonomyNodeTypes;
import org.onehippo.taxonomy.plugin.api.EditableCategory;
import org.onehippo.taxonomy.plugin.api.EditableCategoryInfo;
import org.onehippo.taxonomy.plugin.api.TaxonomyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JcrCategory extends TaxonomyObject implements EditableCategory {
private static final Logger LOG = LoggerFactory.getLogger(JcrCategory.class);
private static final long serialVersionUID = 4494723358209679816L;
public JcrCategory(IModel<Node> nodeModel, boolean editable) throws TaxonomyException {
super(nodeModel, editable);
try {
final Node node = getNode();
if (!node.isNodeType(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_CATEGORY)) {
throw new TaxonomyException("Node " + node.getPath() + " is not of type "
+ TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_CATEGORY);
}
} catch (RepositoryException re) {
throw new TaxonomyException("Error accessing node while creating JcrCategory object", re);
}
}
@Override
public List<EditableCategory> getChildren() {
List<EditableCategory> result = new LinkedList<EditableCategory>();
try {
final Node node = getNode();
final String nodePath = node.getPath();
for (NodeIterator iter = node.getNodes(); iter.hasNext();) {
Node child = iter.nextNode();
if (child != null) {
try {
if (child.isNodeType(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_CATEGORY)) {
result.add(toCategory(new JcrNodeModel(child), editable));
}
} catch (RepositoryException re) {
if (LOG.isDebugEnabled()) {
LOG.debug("Can't create a child category below " + nodePath, re);
} else {
LOG.warn("Can't create a child category below {}, message is {}", nodePath, re.getMessage());
}
} catch (TaxonomyException te) {
LOG.warn("TaxonomyException: can't create a child category below {}, message is {}" + nodePath,
te.getMessage());
}
}
}
} catch (RepositoryException ex) {
LOG.error("Failure getting category children", ex);
}
return result;
}
@Override
public String getName() {
return new NodeTranslator(getNodeModel()).getNodeName().getObject();
}
@Override
public Category getParent() {
try {
Node node = getNode();
Node parent = node.getParent();
if (parent.isNodeType(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_CATEGORY)) {
return toCategory(new JcrNodeModel(parent), editable);
}
} catch (TaxonomyException te) {
LOG.error("Parent not accessible", te);
} catch (RepositoryException ex) {
LOG.error(ex.getMessage());
}
return null;
}
@Override
public List<? extends EditableCategory> getAncestors() {
List<JcrCategory> ancestors = new LinkedList<JcrCategory>();
ancestors.add(this);
try {
Node node = getNode();
while (node.getDepth() > 0) {
Node parent = node.getParent();
if (parent.isNodeType(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_CATEGORY)) {
ancestors.add(toCategory(new JcrNodeModel(parent), editable));
} else if (parent.isNodeType(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_TAXONOMY)) {
break;
}
node = parent;
}
Collections.reverse(ancestors);
} catch (TaxonomyException te) {
LOG.error("Can't create accurate list of ancestors", te.getMessage());
} catch (RepositoryException ex) {
LOG.error(ex.getMessage());
}
return ancestors;
}
@Override
public String getPath() {
List<? extends Category> ancestors = getAncestors();
StringBuilder path = new StringBuilder();
for (Category ancestor : ancestors) {
path.append(ancestor.getName());
path.append("/");
}
return path.toString();
}
@Override
public JcrTaxonomy getTaxonomy() {
try {
Node node = getNode();
while (node.getDepth() > 0) {
Node parent = node.getParent();
if (parent.isNodeType(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_TAXONOMY)) {
return toTaxonomy(new JcrNodeModel(parent), editable);
}
node = parent;
}
} catch (RepositoryException ex) {
LOG.error(ex.getMessage());
}
return null;
}
@Override
public String getKey() {
try {
Node node = getNode();
return node.getProperty(TaxonomyNodeTypes.HIPPOTAXONOMY_KEY).getString();
} catch (RepositoryException ex) {
LOG.error(ex.getMessage());
}
return null;
}
@Override
public EditableCategoryInfo getInfo(final String language) {
try {
Node node = getNode();
// <HCT>
if (editable) {
final NodeIterator docChidlren = node.getNodes(HCTTaxonomyNodeTypes.NODENAME_HIPPOTAXONOMY_DOCUMENTS);
if (docChidlren == null || !docChidlren.hasNext()) {
if (!JcrHelper.isNodeType(node, HCTTaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_FACETED)) {
node.addMixin(HCTTaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_FACETED);
}
final Node documents = node.addNode(HCTTaxonomyNodeTypes.NODENAME_HIPPOTAXONOMY_DOCUMENTS,
"hippofacnav:facetnavigation");
documents.setProperty("hippo:docbase",
node.getSession().getNode("/content/documents").getIdentifier());
documents.setProperty("hippofacnav:facets",
new String[] { TaxonomyNodeTypes.HIPPOTAXONOMY_KEYS });
documents.setProperty("hippofacnav:filters",
new String[] { TaxonomyNodeTypes.HIPPOTAXONOMY_KEYS + "=" + this.getKey() });
documents.setProperty("hippofacnav:limit", 10000);
}
}
// </HCT>
if (JcrHelper.isNodeType(node, TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_TRANSLATED)) {
NodeIterator translations = node.getNodes(TaxonomyNodeTypes.HIPPOTAXONOMY_TRANSLATION);
while (translations.hasNext()) {
Node child = translations.nextNode();
if (child != null) {
try {
String lang = child.getProperty(HippoNodeType.HIPPO_LANGUAGE).getString();
if (lang.equals(language)) {
return new JcrCategoryInfo(new JcrNodeModel(child), editable);
}
} catch (PathNotFoundException pnfe) {
LOG.warn("PathNotFoundException accessing {}", HippoNodeType.HIPPO_LANGUAGE, pnfe);
}
}
}
}
if (editable) {
if (!JcrHelper.isNodeType(node, TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_TRANSLATED)) {
node.addMixin(TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_TRANSLATED);
}
Node child = node.addNode(TaxonomyNodeTypes.HIPPOTAXONOMY_TRANSLATION,
TaxonomyNodeTypes.NODETYPE_HIPPOTAXONOMY_TRANSLATION);
child.setProperty(HippoNodeType.HIPPO_LANGUAGE, language);
child.setProperty(HippoNodeType.HIPPO_MESSAGE, NodeNameCodec.decode(node.getName()));
return new JcrCategoryInfo(new JcrNodeModel(child), editable);
} else {
return new EditableCategoryInfo() {
public void setDescription(String description) throws TaxonomyException {
}
public void setName(String name) throws TaxonomyException {
}
public void setSynonyms(String[] synonyms) throws TaxonomyException {
}
public Node getNode() throws ItemNotFoundException {
return null;
}
public String getDescription() {
return "";
}
public String getLanguage() {
return language;
}
public String getName() {
return JcrCategory.this.getName();
}
public String[] getSynonyms() {
return new String[0];
}
public Map<String, Object> getProperties() {
return Collections.emptyMap();
}
public String getString(String property) {
return "";
}
public String getString(String property, String defaultValue) {
return "";
}
public String[] getStringArray(String property) {
return new String[0];
}
public void setString(String property, String value) throws TaxonomyException {
}
public void setStringArray(String property, String[] values) throws TaxonomyException {
}
};
}
} catch (RepositoryException ex) {
LOG.error(ex.getMessage());
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public Map<String, ? extends CategoryInfo> getInfos() {
Map<String, ? extends CategoryInfo> map = new HashMap<String, EditableCategoryInfo>();
return LazyMap.decorate(map,
new Transformer() {
@Override
public Object transform(Object language) {
return getInfo((String) language);
}
});
}
@Override
public boolean equals(Object obj) {
if (obj instanceof JcrCategory) {
return ((JcrCategory) obj).getNodeModel().equals(getNodeModel());
}
return false;
}
@Override
public int hashCode() {
return getNodeModel().hashCode() ^ 9887;
}
@Override
public JcrCategory addCategory(String key, String name, String locale) throws TaxonomyException {
try {
return createCategory(getNode(), key, name, locale);
} catch (RepositoryException e) {
throw new TaxonomyException("Could not create category with key " + key + ", name " + name + " and locale "
+ locale, e);
}
}
@Override
public void remove() throws TaxonomyException {
checkEditable();
try {
getNode().remove();
} catch (RepositoryException e) {
throw new TaxonomyException("Could not remove category", e);
}
}
}