/* * Copyright 2013, Arondor * * 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 com.arondor.common.reflection.gwt.client.presenter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import com.arondor.common.reflection.gwt.client.event.TreeNodeClearEvent; import com.arondor.common.reflection.gwt.client.service.GWTReflectionServiceAsync; import com.arondor.common.reflection.model.config.ElementConfiguration; import com.arondor.common.reflection.model.config.ObjectConfiguration; import com.arondor.common.reflection.model.config.ObjectConfigurationFactory; import com.arondor.common.reflection.model.config.ObjectConfigurationMap; import com.arondor.common.reflection.model.config.ReferenceConfiguration; import com.arondor.common.reflection.model.java.AccessibleClass; import com.arondor.common.reflection.model.java.AccessibleField; import com.arondor.common.reflection.util.PrimitiveTypeUtil; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.rpc.AsyncCallback; public class ClassTreeNodePresenter implements TreeNodePresenter { private static final Logger LOG = Logger.getLogger(ClassTreeNodePresenter.class.getName()); public interface ClassDisplay extends TreeNodePresenter.ChildCreatorDisplay { ImplementingClassPresenter.Display getImplementingClassDisplay(); } private final Map<String, TreeNodePresenter> classTreeNodePresenterMap = new HashMap<String, TreeNodePresenter>(); private final ClassDisplay display; private final String fieldName; private final ImplementingClassPresenter implementingClassPresenter; private final GWTReflectionServiceAsync rpcService; private final ObjectConfigurationMap objectConfigurationMap; public ClassTreeNodePresenter(GWTReflectionServiceAsync rpcService, ObjectConfigurationMap objectConfigurationMap, String baseClassName, ClassDisplay view) { this(rpcService, objectConfigurationMap, null, baseClassName, view); display.setNodeName(baseClassName); } protected ClassTreeNodePresenter(GWTReflectionServiceAsync rpcService, ObjectConfigurationMap objectConfigurationMap, String fieldName, String baseClassName, ClassDisplay view) { this.fieldName = fieldName; this.rpcService = rpcService; this.display = view; this.objectConfigurationMap = objectConfigurationMap; LOG.finest("Create new TreeNodePresenter for fieldName=" + fieldName + ", baseClassName=" + baseClassName); implementingClassPresenter = new DefaultImplementingClassPresenter(rpcService, objectConfigurationMap, baseClassName, display.getImplementingClassDisplay()); bind(); } private void bind() { implementingClassPresenter.addValueChangeHandler(new ValueChangeHandler<ImplementingClass>() { public void onValueChange(ValueChangeEvent<ImplementingClass> event) { if (event.getValue().isReference()) { classTreeNodePresenterMap.clear(); } else { updateAccessibleClass(event.getValue().getName(), null); } } }); display.addTreeNodeClearHandler(new TreeNodeClearEvent.Handler() { public void onTreeNodeClearEvent(TreeNodeClearEvent treeNodeClearEvent) { implementingClassPresenter.setImplementingClass(ImplementingClass.NULL_CLASS); classTreeNodePresenterMap.clear(); } }); } private void updateAccessibleClass(String className, final ObjectConfiguration objectConfiguration) { rpcService.getAccessibleClass(className, new AsyncCallback<AccessibleClass>() { public void onSuccess(AccessibleClass result) { updateAccessibleClass(result, objectConfiguration); } public void onFailure(Throwable caught) { } }); } private void updateAccessibleClass(AccessibleClass accessibleClass, ObjectConfiguration objectConfiguration) { LOG.finest("field=" + fieldName + ", updateAccessibleClass(class=" + (accessibleClass != null ? accessibleClass.getName() : null) + ", objectConfiguration=" + objectConfiguration + ")"); classTreeNodePresenterMap.clear(); display.clear(); if (accessibleClass != null) { display.setActive(true); buildTree(accessibleClass); if (objectConfiguration != null) { implementingClassPresenter.setImplementingClass(new ImplementingClass(false, objectConfiguration .getClassName())); if (PrimitiveTypeUtil.isPrimitiveType(objectConfiguration.getClassName()) && objectConfiguration.getConstructorArguments().size() == 1) { TreeNodePresenter valuePresenter = classTreeNodePresenterMap.get("value"); if (valuePresenter != null) { valuePresenter.setElementConfiguration(objectConfiguration.getConstructorArguments().get(0)); } } else if (objectConfiguration.getFields() != null) { for (Map.Entry<String, ElementConfiguration> fieldEntry : objectConfiguration.getFields() .entrySet()) { TreeNodePresenter nodePresenter = classTreeNodePresenterMap.get(fieldEntry.getKey()); if (nodePresenter != null) { nodePresenter.setElementConfiguration(fieldEntry.getValue()); } } } } } else { display.setActive(false); } } private void buildTree(AccessibleClass accessibleClass) { List<AccessibleField> sortedAccessibleFields = new ArrayList<AccessibleField>(); sortedAccessibleFields.addAll(accessibleClass.getAccessibleFields().values()); Collections.sort(sortedAccessibleFields, new AccessibleFieldComparator()); LOG.finest("Build tree for accessibleClass=" + accessibleClass.getName()); for (AccessibleField accessibleField : sortedAccessibleFields) { TreeNodePresenter childPresenter = TreeNodePresenterFactory.getInstance().createChildNodePresenter( rpcService, objectConfigurationMap, display, accessibleField); LOG.finest("At field=" + accessibleField.getName() + ", created childPresenter=" + childPresenter); classTreeNodePresenterMap.put(accessibleField.getName(), childPresenter); } } public String getFieldName() { return fieldName; } public String getBaseClassName() { return implementingClassPresenter.getBaseClassName(); } public ClassDisplay getDisplay() { return display; } public ElementConfiguration getElementConfiguration(ObjectConfigurationFactory objectConfigurationFactory) { if (implementingClassPresenter.getImplementingClass() == null || implementingClassPresenter.getImplementingClass().getName() == null) { return null; } if (PrimitiveTypeUtil.isPrimitiveType(implementingClassPresenter.getImplementingClass().getName())) { String implementingClass = implementingClassPresenter.getImplementingClass().getName(); if (implementingClass.equals("java.lang.String")) { /** * This is rather hacky */ TreeNodePresenter valuePresenter = classTreeNodePresenterMap.get("value"); if (valuePresenter != null) { ElementConfiguration valueConfiguration = valuePresenter .getElementConfiguration(objectConfigurationFactory); ObjectConfiguration objectConfiguration = objectConfigurationFactory.createObjectConfiguration(); objectConfiguration.setClassName(implementingClass); objectConfiguration.setFields(new LinkedHashMap<String, ElementConfiguration>()); objectConfiguration.setConstructorArguments(new ArrayList<ElementConfiguration>()); objectConfiguration.getConstructorArguments().add(valueConfiguration); return objectConfiguration; } } throw new RuntimeException("NOT IMPLEMENTED YET"); } else if (implementingClassPresenter.getImplementingClass().isReference()) { ReferenceConfiguration referenceConfiguration = objectConfigurationFactory.createReferenceConfiguration(); referenceConfiguration.setReferenceName(implementingClassPresenter.getImplementingClass().getName()); return referenceConfiguration; } else { return getObjectConfiguration(objectConfigurationFactory); } } private ElementConfiguration getObjectConfiguration(ObjectConfigurationFactory objectConfigurationFactory) { ObjectConfiguration objectConfiguration = objectConfigurationFactory.createObjectConfiguration(); objectConfiguration.setFields(new LinkedHashMap<String, ElementConfiguration>()); objectConfiguration.setClassName(implementingClassPresenter.getImplementingClass().getName()); updateChildObjectConfigurations(objectConfigurationFactory, objectConfiguration); return objectConfiguration; } private void updateChildObjectConfigurations(ObjectConfigurationFactory objectConfigurationFactory, ObjectConfiguration objectConfiguration) { for (Map.Entry<String, TreeNodePresenter> presentersEntry : classTreeNodePresenterMap.entrySet()) { ElementConfiguration childConfiguration = presentersEntry.getValue().getElementConfiguration( objectConfigurationFactory); if (childConfiguration != null) { objectConfiguration.getFields().put(presentersEntry.getKey(), childConfiguration); } } } public void setElementConfiguration(ElementConfiguration elementConfiguration) { LOG.finest("setElementConfiguration :" + elementConfiguration); if (elementConfiguration instanceof ObjectConfiguration) { ObjectConfiguration objectConfiguration = (ObjectConfiguration) elementConfiguration; updateAccessibleClass(objectConfiguration.getClassName(), objectConfiguration); } else if (elementConfiguration instanceof ReferenceConfiguration) { ReferenceConfiguration referenceConfiguration = (ReferenceConfiguration) elementConfiguration; implementingClassPresenter.setImplementingClass(new ImplementingClass(true, referenceConfiguration .getReferenceName())); } } public ImplementingClass getImplementingClass() { return implementingClassPresenter.getImplementingClass(); } }