Java tutorial
/** * * Copyright 2016 by Jan Haderka <jan.haderka@neatresults.com> * * This file is part of neat-u2b module. * * Neat-u2b is free software: you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * Neat-tweaks is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with neat-u2b. If not, see <http://www.gnu.org/licenses/>. * * @license GPL-3.0 <http://www.gnu.org/licenses/gpl.txt> * * Should you require distribution under alternative license in order to * use neat-u2b commercially, please contact owner at the address above. * */ package com.neatresults.mgnltweaks.neatu2b.ui.form.field.composite; import info.magnolia.jcr.iterator.FilteringPropertyIterator; import info.magnolia.jcr.predicate.JCRMgnlPropertyHidingPredicate; import info.magnolia.jcr.util.NodeTypes; import info.magnolia.jcr.util.NodeUtil; import info.magnolia.jcr.wrapper.JCRMgnlPropertiesFilteringNodeWrapper; import info.magnolia.module.ModuleRegistry; import info.magnolia.objectfactory.Components; import info.magnolia.registry.RegistrationException; import info.magnolia.rest.client.registry.RestClientRegistry; import info.magnolia.resteasy.client.RestEasyClient; import info.magnolia.ui.form.field.transformer.composite.CompositeTransformer; import info.magnolia.ui.vaadin.integration.jcr.DefaultProperty; import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter; import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.PropertyIterator; import javax.jcr.RepositoryException; import org.apache.commons.lang3.StringUtils; import org.codehaus.jackson.JsonNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.neatresults.mgnltweaks.neatu2b.NeatU2b; import com.neatresults.mgnltweaks.neatu2b.restclient.U2BService; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.util.PropertysetItem; /** * Expands single field with youtube video id/link to set of fields containing also metadata about the video. * * Quick and dirty ... just an example, not to be used in production! Use U2BField instead. */ public class CompositeU2BFieldTransformer extends CompositeTransformer { private static final Logger log = LoggerFactory.getLogger(CompositeU2BFieldTransformer.class); protected List<String> fieldsName; private final RestClientRegistry restClientRegistry; private final NeatU2b u2bModule; private CompositeU2BFieldDefinition u2bDefinition; @Inject public CompositeU2BFieldTransformer(Item relatedFormItem, CompositeU2BFieldDefinition definition, Class<PropertysetItem> type, List<String> fieldsName) { super(relatedFormItem, definition, type, fieldsName); this.restClientRegistry = Components.getComponent(RestClientRegistry.class); this.u2bModule = Components.getComponent(ModuleRegistry.class).getModuleInstance(NeatU2b.class); this.u2bDefinition = definition; } @Override protected String getCompositePropertyName(String propertyName) { if (propertyName.equals("Id")) { return propertyPrefix; } return super.getCompositePropertyName(propertyName); } @Override public void writeToItem(PropertysetItem newValues) { Property prop = relatedFormItem.getItemProperty(this.propertyPrefix); // initialize rest service RestEasyClient client = null; U2BService service = null; try { client = (RestEasyClient) restClientRegistry.getRestClient("youtube"); service = client.getClientService(U2BService.class); } catch (RegistrationException e) { log.error("Failed to get a client for [" + U2BService.class.getName() + "] with: " + e.getMessage(), e); } if (service != null) { // extract video id from the string that might be url or id String id = getVideoId(prop); String key = u2bModule.getGoogleKey(); // call service w/ id to get the metadata JsonNode response = service.meta(id, "snippet", key); try { if (response.get("items").getElements().hasNext()) { JsonNode videoItem = response.get("items").getElements().next(); JsonNode snippet = videoItem.get("snippet"); setNewValue(relatedFormItem, snippet, "description"); setNewValue(relatedFormItem, snippet, "title"); setNewValue(relatedFormItem, snippet, "publishedAt"); Iterator<Entry<String, JsonNode>> thumbs = videoItem.get("snippet").get("thumbnails") .getFields(); String thumbsName = getCompositePropertyName("Thumbs"); JcrNodeAdapter thumbsParent = getOrCreateChildItem((JcrNodeAdapter) relatedFormItem, thumbsName); while (thumbs.hasNext()) { Entry<String, JsonNode> entry = thumbs.next(); JcrNodeAdapter thumbChild = getOrCreateChildItem(thumbsParent, entry.getKey()); String propId = "url"; thumbChild.removeItemProperty(propId); thumbChild.addItemProperty(propId, new DefaultProperty<String>(String.class, entry.getValue().get(propId).getTextValue())); // need to get those as longs not as text!! propId = "width"; thumbChild.removeItemProperty(propId); thumbChild.addItemProperty(propId, new DefaultProperty<Long>(Long.class, entry.getValue().get(propId).getLongValue())); propId = "height"; thumbChild.removeItemProperty(propId); thumbChild.addItemProperty(propId, new DefaultProperty<Long>(Long.class, entry.getValue().get(propId).getLongValue())); thumbsParent.addChild(thumbChild); } ((JcrNodeAdapter) relatedFormItem).addChild(thumbsParent); } } catch (Exception e) { log.error("Failed to parse the video metadata.", e); } response = service.meta(id, "contentDetails", key); try { if (response.get("items").getElements().hasNext()) { JsonNode videoItem = response.get("items").getElements().next(); setNewValue(relatedFormItem, videoItem.get("contentDetails"), "duration"); setNewValue(relatedFormItem, videoItem.get("contentDetails"), "definition"); } } catch (Exception e) { log.error("Failed to parse the video duration.", e); } } } private void setNewValue(Item relatedFormItem, JsonNode snippet, String fieldName) { String value = snippet.get(fieldName).getTextValue(); String compositePropertyName = getCompositePropertyName(StringUtils.capitalize(fieldName)); relatedFormItem.addItemProperty(compositePropertyName, new DefaultProperty<String>(String.class, value)); } public String getVideoId(Property<?> prop) { if (prop == null) { throw new NullPointerException( "Video is not set or name of the required field for this dialog is not correctly configured."); } String maybeId = (String) prop.getValue(); if (maybeId == null) { return null; } if (maybeId.startsWith("http")) { maybeId = StringUtils.substringBefore(StringUtils.substringAfter(maybeId, "?v="), "&"); } return maybeId; } /** * Return the child item containing the properties (displayed in the multiField). */ private JcrNodeAdapter getOrCreateChildItem(JcrNodeAdapter parent, String childNodeName) throws RepositoryException { JcrNodeAdapter child = null; Node rootNode = parent.getJcrItem(); if (rootNode.hasNode(childNodeName)) { child = new JcrNodeAdapter(rootNode.getNode(childNodeName)); Node childNode = new JCRMgnlPropertiesFilteringNodeWrapper(rootNode.getNode(childNodeName)); PropertyIterator iterator = childNode.getProperties(); while (iterator.hasNext()) { // Make sure we populate the adapter with existing JCR properties. child.getItemProperty(iterator.nextProperty().getName()); } } else { child = new JcrNewNodeAdapter(rootNode, NodeTypes.ContentNode.NAME, childNodeName); } parent.addChild(child); return child; } @Override public PropertysetItem readFromItem() { // read all the normal/basic fields from the parent PropertysetItem supsi = super.readFromItem(); // fake the ID as we are forcing that to be stored just as the prefix supsi.addItemProperty("Id", supsi.getItemProperty(propertyPrefix)); // manually load props from subnodes (just like simplified version of MultivalueSubnodeTransformer) try { String thumbsName = getCompositePropertyName("Thumbs"); JcrNodeAdapter thumbsParent = getOrCreateChildItem((JcrNodeAdapter) relatedFormItem, thumbsName); PropertysetItem psi = new PropertysetItem(); // Get a list of childNodes List<Node> childNodes = NodeUtil.asList(NodeUtil.getNodes(thumbsParent.getJcrItem())); int position = 0; for (Node child : childNodes) { PropertysetItem cpsi = new PropertysetItem(); PropertyIterator cProps = new FilteringPropertyIterator(child.getProperties(), new JCRMgnlPropertyHidingPredicate()); while (cProps.hasNext()) { javax.jcr.Property cProp = cProps.nextProperty(); cpsi.addItemProperty(cProp.getName(), new DefaultProperty<String>(String.class, cProp.getString())); } psi.addItemProperty(position, new DefaultProperty<PropertysetItem>(PropertysetItem.class, cpsi)); position += 1; } supsi.addItemProperty("Thumbs", new DefaultProperty<PropertysetItem>(PropertysetItem.class, psi)); } catch (RepositoryException e) { log.error(e.getMessage(), e); } /* * for (ConfiguredFieldDefinition field : u2bDefinition.getFields()) { if (field.getName() == null || !field.getName().equals("Id")) { field.setReadOnly(true); } } */ return supsi; } }