Package org.auraframework.impl.root.component

Source Code of org.auraframework.impl.root.component.BaseComponentImpl

/*
* Copyright (C) 2013 salesforce.com, inc.
*
* 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.auraframework.impl.root.component;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.auraframework.Aura;
import org.auraframework.def.AttributeDef;
import org.auraframework.def.AttributeDefRef;
import org.auraframework.def.BaseComponentDef;
import org.auraframework.def.ComponentDefRefArray;
import org.auraframework.def.ControllerDef;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.InterfaceDef;
import org.auraframework.def.ModelDef;
import org.auraframework.def.RendererDef;
import org.auraframework.def.RootDefinition;
import org.auraframework.def.TypeDef;
import org.auraframework.expression.PropertyReference;
import org.auraframework.impl.java.model.JavaModel;
import org.auraframework.impl.root.AttributeDefImpl;
import org.auraframework.impl.root.AttributeSetImpl;
import org.auraframework.impl.system.DefDescriptorImpl;
import org.auraframework.instance.Action;
import org.auraframework.instance.AttributeSet;
import org.auraframework.instance.BaseComponent;
import org.auraframework.instance.Component;
import org.auraframework.instance.Instance;
import org.auraframework.instance.InstanceStack;
import org.auraframework.instance.Model;
import org.auraframework.instance.ValueProvider;
import org.auraframework.instance.ValueProviderType;
import org.auraframework.service.LoggingService;
import org.auraframework.system.AuraContext;
import org.auraframework.system.MasterDefRegistry;
import org.auraframework.throwable.AuraRuntimeException;
import org.auraframework.throwable.quickfix.DefinitionNotFoundException;
import org.auraframework.throwable.quickfix.MissingRequiredAttributeException;
import org.auraframework.throwable.quickfix.QuickFixException;
import org.auraframework.util.AuraTextUtil;
import org.auraframework.util.json.Json;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public abstract class BaseComponentImpl<D extends BaseComponentDef, I extends BaseComponent<D, I>> implements
        BaseComponent<D, I> {
    /**
     * Top level component instance with attributes passed in. Builds out the tree recursively, but only after the
     * attribute values are all set.
     *
     * @param descriptor
     * @param attributes
     * @throws QuickFixException
     */
    public BaseComponentImpl(DefDescriptor<D> descriptor, Map<String, Object> attributes) throws QuickFixException {
        this(descriptor, null, (Map<String, Object>) null, null, null);
        LoggingService loggingService = Aura.getLoggingService();
        loggingService.startTimer(LoggingService.TIMER_COMPONENT_CREATION);
        try {
            this.attributeSet.set(attributes);
            finishInit();
        } finally {
            loggingService.stopTimer(LoggingService.TIMER_COMPONENT_CREATION);
        }
        Aura.getContextService().getCurrentContext().getInstanceStack().popInstance(this);
    }

    @SuppressWarnings("unchecked")
    public <T extends D> BaseComponentImpl(T def, Map<String, Object> attributes) throws QuickFixException {
        this((DefDescriptor<D>) def.getDescriptor(), null, (Map<String, Object>) null, null, def);
        LoggingService loggingService = Aura.getLoggingService();
        loggingService.startTimer(LoggingService.TIMER_COMPONENT_CREATION);
        try {
            this.attributeSet.set(attributes);
            finishInit();
        } finally {
            loggingService.stopTimer(LoggingService.TIMER_COMPONENT_CREATION);
        }
        Aura.getContextService().getCurrentContext().getInstanceStack().popInstance(this);
    }

    /**
     * Constructor used to create instances for all ComponentDefRefs, which come from both the children and the facets
     * (attributes). Builds out the tree recursively, but only after all the attribute values, including facets are set.
     *
     * @throws QuickFixException
     */
    public BaseComponentImpl(DefDescriptor<D> descriptor, Collection<AttributeDefRef> attributeDefRefs,
            BaseComponent<?, ?> attributeValueProvider, String localId) throws QuickFixException {
        this(descriptor, attributeValueProvider, null, null, null);
        LoggingService loggingService = Aura.getLoggingService();
        loggingService.startTimer(LoggingService.TIMER_COMPONENT_CREATION);
        try {
            this.attributeSet.set(attributeDefRefs);
            finishInit();
        } finally {
            loggingService.stopTimer(LoggingService.TIMER_COMPONENT_CREATION);
        }
        Aura.getContextService().getCurrentContext().getInstanceStack().popInstance(this);
        this.localId = localId;
    }

    /**
     * For creating supers
     *
     * @throws QuickFixException
     */
    protected BaseComponentImpl(DefDescriptor<D> descriptor, I extender, BaseComponent<?, ?> attributeValueProvider,
            I concreteComponent) throws QuickFixException {
        this(descriptor, attributeValueProvider, null, extender, null);
        LoggingService loggingService = Aura.getLoggingService();
        loggingService.startTimer(LoggingService.TIMER_COMPONENT_CREATION);
        try {
            this.concreteComponent = concreteComponent;
            attributeSet.set(extender.getDescriptor().getDef().getFacets(), extender.getAttributes());
            finishInit();
        } finally {
            loggingService.stopTimer(LoggingService.TIMER_COMPONENT_CREATION);
        }
        Aura.getContextService().getCurrentContext().getInstanceStack().popInstance(this);
    }

    /**
     * The base constructor that the other 2 use to initialize the object, but not he attributes. Sets all defaults for
     * attributes. Does not build out the tree recursively.
     *
     * @param descriptor The descriptor for this component's definition
     * @param def TODO
     * @throws QuickFixException
     */
    private BaseComponentImpl(DefDescriptor<D> descriptor, BaseComponent<?, ?> attributeValueProvider,
            Map<String, Object> valueProviders, I extender, D def) throws QuickFixException {
        AuraContext context = Aura.getContextService().getCurrentContext();
        DefDescriptor<? extends RootDefinition> desc = null;

        InstanceStack instanceStack = context.getInstanceStack();
        Instance<?> parent = instanceStack.peek();

        this.descriptor = descriptor;
        this.originalDescriptor = descriptor;
        this.path = instanceStack.getPath();
        instanceStack.pushInstance(this, descriptor);

        if (def == null) {
            try {
                def = descriptor.getDef();
                if (extender == null && (def.isAbstract() || def.getLocalProviderDef() != null)) {
                    this.intfDescriptor = def.getDescriptor();
                }

                desc = descriptor;
            } catch (DefinitionNotFoundException e) {
                if (!e.getDescriptor().equals(descriptor)) {
                    throw e;
                }

                DefDescriptor<InterfaceDef> intfDescriptor = DefDescriptorImpl.getInstance(
                        descriptor.getQualifiedName(), InterfaceDef.class);
                InterfaceDef intfDef = intfDescriptor.getDef();
                if (intfDef != null) {
                    this.intfDescriptor = intfDescriptor;
                    desc = intfDescriptor;
                } else {
                    // def not found
                    throw new DefinitionNotFoundException(descriptor);
                }
            }
        } else {
            desc = descriptor;
        }

        MasterDefRegistry defRegistry = Aura.getDefinitionService().getDefRegistry();
        if (parent != null) {
            // Insure that the parent is allowed to create an instance of this component
            defRegistry.assertAccess(parent.getDescriptor(), desc.getDef());
        }

        LoggingService loggingService = Aura.getLoggingService();
        loggingService.startTimer(LoggingService.TIMER_COMPONENT_CREATION);
        try {
            this.globalId = getNextGlobalId();

            this.attributeSet = new AttributeSetImpl(desc, attributeValueProvider, this);

            if (valueProviders != null) {
                this.valueProviders.putAll(valueProviders);
            }

            this.valueProviders.put(ValueProviderType.VIEW.getPrefix(), attributeSet);

            // def can be null if a definition not found exception was thrown for that definition. Odd.
            if (def != null) {
                ControllerDef cd = def.getDeclaredControllerDef();
                if (cd != null) {
                    // Insure that this def is allowed to create an instance of the controller
                    defRegistry.assertAccess(descriptor, cd);

                    this.valueProviders.put(ValueProviderType.CONTROLLER.getPrefix(), cd);
                }
            }

            loggingService.incrementNum(LoggingService.CMP_COUNT);
        } finally {
            loggingService.stopTimer(LoggingService.TIMER_COMPONENT_CREATION);
        }
    }

    protected void finishInit() throws QuickFixException {
        AuraContext context = Aura.getContextService().getCurrentContext();

        injectComponent();
        createModel();

        context.getInstanceStack().setAttributeName("$");
        createSuper();
        context.getInstanceStack().clearAttributeName("$");

        validateAttributes();

        BaseComponentDef def = getComponentDef();

        def.retrieveLabels();

        DefDescriptor<RendererDef> rendererDesc = def.getRendererDescriptor();
        if ((rendererDesc != null && rendererDesc.getDef().isLocal())) {
            hasLocalDependencies = true;
        }
        context.registerComponent(this);
    }

    private Object findValue(String name) throws QuickFixException {
        BaseComponent<?, ?> zuper = this.getSuper();
        while (zuper != null) {
            Object val = zuper.getAttributes().getValue(name);
            if (val != null) {
                return val;
            }
            zuper = zuper.getSuper();
        }
        return null;
    }

    private void validateAttributes() throws QuickFixException {
        Set<AttributeDef> missingAttributes = attributeSet.getMissingAttributes();
        if (missingAttributes != null && !missingAttributes.isEmpty()) {
            for (AttributeDef attr : missingAttributes) {
                if (this.findValue(attr.getName()) == null) {
                    DefDescriptor<? extends RootDefinition> desc = attributeSet.getRootDefDescriptor();
                    if (attributeSet.getValueProvider() != null) {
                        desc = attributeSet.getValueProvider().getDescriptor();
                    }

                    throw new MissingRequiredAttributeException(desc, attr.getName(), attr.getLocation());
                }
            }
        }
    }

    protected abstract void createSuper() throws DefinitionNotFoundException, QuickFixException;

    protected abstract void injectComponent() throws QuickFixException;

    public D getComponentDef() throws QuickFixException {
        return descriptor.getDef();
    }

    @Override
    public DefDescriptor<D> getDescriptor() {
        return descriptor;
    }

    @Override
    public String getGlobalId() {
        return globalId;
    }

    @Override
    public String getLocalId() {
        return localId;
    }

    /**
     * @return All of the Attributes for this Component
     */
    @Override
    public AttributeSet getAttributes() {
        return attributeSet;
    }

    /**
     * this is only to serialize the general shape and ids, to ensure that we generate the same stuff in the client
     */
    @Override
    public void serialize(Json json) throws IOException {
        AuraContext context = Aura.getContextService().getCurrentContext();
        BaseComponent<?, ?> oldComponent = context.setCurrentComponent(this);

        try {
            BaseComponentDef def = getComponentDef();

            json.writeMapBegin();
            //
            // Be very careful here. descriptor != def.getDescriptor().
            // This is 'case normalizing', as the client is actually case
            // sensitive for descriptors (ugh!).
            //
            json.writeMapEntry("componentDef", def.getDescriptor());
            if (!descriptor.equals(originalDescriptor)) {
                json.writeMapEntry("original", originalDescriptor);
            }
            json.writeMapEntry("creationPath", getPath());

            if ((attributeSet.getValueProvider() == null || hasProvidedAttributes) && !attributeSet.isEmpty()) {
                json.writeMapEntry("attributes", attributeSet);
            }

            if (def.getRendererDescriptor() != null) {
                RendererDef rendererDef = def.getRendererDescriptor().getDef();
                if (rendererDef.isLocal()) {
                    StringWriter sw = new StringWriter();
                    rendererDef.render(this, sw);
                    // Not writing directly to json.appendable because then it wouldn't get escaped.
                    // ideally Json would have a FilterWriter that escapes that we could use here.
                    json.writeMapEntry("rendering", sw.toString());
                }
            }

            if (model != null && model.getDescriptor().getDef().hasMembers()) {
                json.writeMapEntry("model", model);
            }

            json.writeMapEnd();
        } catch (QuickFixException e) {
            throw new AuraRuntimeException(e);
        } finally {
            context.setCurrentComponent(oldComponent);
        }
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("%s {%s}", descriptor.toString(), getGlobalId());
    }

    /**
     * instantiates the model
     *
     * @throws QuickFixException
     */
    private void createModel() throws QuickFixException {
        AuraContext context = Aura.getContextService().getCurrentContext();
        context.pushCallingDescriptor(descriptor);
        BaseComponent<?, ?> oldComponent = context.setCurrentComponent(this);
        try {
            ModelDef modelDef = getComponentDef().getModelDef();
            if (modelDef != null) {
                Aura.getDefinitionService().getDefRegistry().assertAccess(descriptor, modelDef);

                model = modelDef.newInstance();
                if (modelDef.hasMembers()) {
                    hasLocalDependencies = true;
                    valueProviders.put(ValueProviderType.MODEL.getPrefix(), model);
                }
            }
        } finally {
            context.setCurrentComponent(oldComponent);
            context.popCallingDescriptor();
        }
    }

    /**
     * @return the next id to use, the ordering must match exactly what is generated client side
     */
    private static String getNextGlobalId() {
        AuraContext context = Aura.getContextService().getCurrentContext();
        String num = Aura.getContextService().getCurrentContext().getNum();
        Action action = context.getCurrentAction();
        int id;
        String suffix;
        if (action != null) {
            id = action.getInstanceStack().getNextId();
            suffix = action.getId();
        } else {
            id = context.getNextId();
            suffix = num;
        }

        String globalId = String.valueOf(id);
        if (suffix != null) {
            globalId = String.format("%s:%s", globalId, suffix);
        }

        return globalId;
    }

    @Override
    public boolean hasLocalDependencies() {
        return hasLocalDependencies;
    }

    @Override
    public Object getValue(PropertyReference expr) throws QuickFixException {
        AuraContext context = Aura.getContextService().getCurrentContext();
        BaseComponent<?, ?> oldComponent = context.setCurrentComponent(this);
        try {
            String prefix = expr.getRoot();
            if ("c".equals(prefix)) {
                prefix.toString();
            }
            PropertyReference stem = expr.getStem();

            Object root = valueProviders.get(prefix);
            if (root == null) {
                ValueProviderType vpt = ValueProviderType.getTypeByPrefix(prefix);
                if (vpt != null) {
                    root = context.getGlobalProviders().get(vpt);
                }
            }
            if (root != null) {
                if (stem != null) {
                    if (root instanceof ValueProvider) {
                        return ((ValueProvider) root).getValue(stem);
                    } else {
                        return JavaModel.getValue(root, stem, null);
                        // no throw error at runtime even though expression
                        // reference nothing
                        // return null;
                    }
                } else {
                    // they asked for just the root.
                    // TODO: this should only work for foreach, shouldn't be
                    // able to {!m}
                    return root;
                }
            }
            return null;
        } finally {
            context.setCurrentComponent(oldComponent);
        }
    }

    @Override
    public void index(Component component) {
        String id = component.getLocalId();
        if (!AuraTextUtil.isNullEmptyOrWhitespace(id)) {
            List<String> globalIds = index.get(id);
            if (globalIds == null) {
                globalIds = Lists.newArrayList();
                index.put(id, globalIds);
            }
            globalIds.add(component.getGlobalId());
        }
    }

    @Override
    public I getSuper() {
        return superComponent;
    }

    @Override
    public Model getModel() {
        return model;
    }

    @Override
    public String getPath() {
        return path;
    }

    static private DefDescriptor<TypeDef> componentArrType;
    static private DefDescriptor<TypeDef> componentDefRefArrayType;

    @Override
    public void reinitializeModel() throws QuickFixException {
        //
        // This is a visitor pattern, implemented here with a hardwire.
        //
        BaseComponentDef def = descriptor.getDef();
        if (componentArrType == null) {
            componentArrType = Aura.getDefinitionService().getDefDescriptor("aura://Aura.Component[]", TypeDef.class);
        }
       
        if(componentDefRefArrayType == null) {
          componentDefRefArrayType = Aura.getDefinitionService().getDefDescriptor("aura://Aura.ComponentDefRef[]", TypeDef.class);
        }

        createModel();

        I zuper = getSuper();
        if (zuper != null) {
            zuper.reinitializeModel();
        }
        //
        // Walk all attributes, pushing the reinitialize model in to those as well.
        //
        for (Map.Entry<DefDescriptor<AttributeDef>, AttributeDef> foo : def.getAttributeDefs().entrySet()) {
            AttributeDef attr = foo.getValue();
            DefDescriptor<?> typeDesc;
            if (attr instanceof AttributeDefImpl) {
                AttributeDefImpl attri = (AttributeDefImpl) attr;
                typeDesc = attri.getTypeDesc();
            } else {
                // bad.
                typeDesc = attr.getTypeDef().getDescriptor();
            }
            if (componentArrType.equals(typeDesc)) {
                Object val = getAttributes().getValue(foo.getKey().getName());
                if (val instanceof List) {
                    @SuppressWarnings("unchecked")
                    List<BaseComponent<?, ?>> facet = (List<BaseComponent<?, ?>>) val;
                    for (BaseComponent<?, ?> c : facet) {
                        c.reinitializeModel();
                    }
                }
            }
            else if (componentDefRefArrayType.equals(typeDesc)) {
              ComponentDefRefArray val = getAttributes().getValue(foo.getKey().getName(), ComponentDefRefArray.class);
                if (val != null) {
                    //@SuppressWarnings("unchecked")
                    //List<BaseComponent<?, ?>> facet = (List<BaseComponent<?, ?>>) val;
                    for (Object c : val.getList()) {
                      if(c instanceof BaseComponent) {
                        ((BaseComponent<?, ?>)c).reinitializeModel();                       
                      }
                    }
                }
            }
           
        }
    }

    protected final DefDescriptor<D> originalDescriptor;
    protected DefDescriptor<D> descriptor;
    protected DefDescriptor<? extends RootDefinition> intfDescriptor;
    private final String globalId;
    private final String path;
    protected String localId;
    protected final AttributeSet attributeSet;
    private Model model;
    protected I superComponent;
    protected I concreteComponent;
    protected boolean remoteProvider = false;
    private final Map<String, List<String>> index = Maps.newLinkedHashMap();
    // FIXME - the values should be ValueProviders, but first we need to wrap non-m/v/c providers.
    protected final Map<String, Object> valueProviders = new LinkedHashMap<String, Object>();
    protected boolean hasLocalDependencies = false;
    protected boolean hasProvidedAttributes;
}
TOP

Related Classes of org.auraframework.impl.root.component.BaseComponentImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.