org.auraframework.impl.css.token.TokenCacheImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.auraframework.impl.css.token.TokenCacheImpl.java

Source

/*
 * 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.css.token;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.auraframework.Aura;
import org.auraframework.css.TokenCache;
import org.auraframework.def.DefDescriptor;
import org.auraframework.def.TokenDef;
import org.auraframework.def.TokenMapProviderDef;
import org.auraframework.def.TokensDef;
import org.auraframework.impl.java.provider.TokenMapProviderInstance;
import org.auraframework.service.DefinitionService;
import org.auraframework.throwable.quickfix.QuickFixException;
import org.auraframework.util.text.Hash;

import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

public final class TokenCacheImpl implements TokenCache {
    private final Multimap<DefDescriptor<TokensDef>, DefDescriptor<TokensDef>> originals;
    private final ImmutableList<DefDescriptor<TokensDef>> descriptors;
    private final ImmutableList<DefDescriptor<TokensDef>> reversed;
    private final ImmutableTable<String, DefDescriptor<TokensDef>, String> dynamicTokens;
    private final DefinitionService definitionService;

    public TokenCacheImpl(DefinitionService definitionService, Iterable<DefDescriptor<TokensDef>> descriptors)
            throws QuickFixException {
        checkNotNull(descriptors, "descriptors cannot be null, see EmptyTokenCache instead");
        this.definitionService = definitionService;

        // we want a unique list of the concrete descs. Since last one wins, there's no need to include duplicate
        // entries; just the last one. duplicate entries could come from descriptor providers that resolve to the
        // same descriptor, or just user error/inefficiency
        Set<DefDescriptor<TokensDef>> unique = new LinkedHashSet<>();

        // in the case of descriptor providers, maintain a mapping to the original descriptor(s)
        ImmutableMultimap.Builder<DefDescriptor<TokensDef>, DefDescriptor<TokensDef>> origs = ImmutableMultimap
                .builder();

        for (DefDescriptor<TokensDef> descriptor : descriptors) {
            DefDescriptor<TokensDef> concrete = definitionService.getDefinition(descriptor).getConcreteDescriptor();
            unique.remove(concrete); // unlike the normal behavior, we want to move the position of duplicate entries
            unique.add(concrete);
            if (descriptor != concrete) {
                origs.put(concrete, descriptor);
            }
        }

        this.originals = origs.build();
        this.descriptors = ImmutableList.copyOf(unique);
        this.reversed = this.descriptors.reverse();

        ImmutableTable.Builder<String, DefDescriptor<TokensDef>, String> table = ImmutableTable.builder();
        for (DefDescriptor<TokensDef> descriptor : this.descriptors) { // iterate through the unique list
            TokensDef def = definitionService.getDefinition(descriptor);
            if (def.getMapProvider() != null) {
                TokenMapProviderDef tokenMapProviderDef = definitionService.getDefinition(def.getMapProvider());
                TokenMapProviderInstance instance = Aura.getInstanceService().getInstance(tokenMapProviderDef);
                Map<String, String> map = instance.provide();
                for (Entry<String, String> entry : map.entrySet()) {
                    table.put(entry.getKey(), descriptor, entry.getValue());
                }
            }
        }
        this.dynamicTokens = table.build();
    }

    @Override
    public int size() {
        return descriptors.size();
    }

    @Override
    public boolean isEmpty() {
        return descriptors.isEmpty();
    }

    @Override
    public Iterator<DefDescriptor<TokensDef>> iterator() {
        return descriptors.iterator(); // descriptors is already unmodifiable
    }

    @Override
    public List<DefDescriptor<TokensDef>> orderedForEvaluation() {
        return reversed;
    }

    @Override
    public Optional<Object> getToken(String name) throws QuickFixException {
        for (DefDescriptor<TokensDef> descriptor : reversed) { // reverse order; last one wins
            TokensDef def = definitionService.getDefinition(descriptor);

            Optional<Object> value = def.getToken(name);
            if (value.isPresent()) {
                return value;
            }
            if (def.getMapProvider() != null) {
                value = Optional.<Object>fromNullable(dynamicTokens.get(name, descriptor));
            }
            if (value.isPresent()) {
                return value;
            }
        }

        return Optional.absent();
    }

    @Override
    public Optional<TokenDef> getRelevantTokenDef(String name) throws QuickFixException {
        for (DefDescriptor<TokensDef> descriptor : reversed) { // reverse order; last one wins
            Optional<TokenDef> def = definitionService.getDefinition(descriptor).getTokenDef(name);
            if (def.isPresent()) {
                return def;
            }
        }

        return Optional.absent();
    }

    @Override
    public boolean hasDynamicTokens() {
        return !dynamicTokens.isEmpty();
    }

    @Override
    public Map<String, String> activeDynamicTokens() {
        Map<String, String> map = Maps.newHashMap();

        // no need to consult #orderedForEvaluation because we are using a map
        for (DefDescriptor<TokensDef> descriptor : descriptors) {
            map.putAll(dynamicTokens.column(descriptor));
        }
        return map;
    }

    @Override
    public Set<String> getNames(Iterable<DefDescriptor<TokensDef>> f) throws QuickFixException {
        final Set<DefDescriptor<TokensDef>> filter = f != null ? ImmutableSet.copyOf(f) : null;
        Set<String> names = new HashSet<>();

        final Predicate<DefDescriptor<TokensDef>> predicate = new Predicate<DefDescriptor<TokensDef>>() {
            @Override
            public boolean apply(DefDescriptor<TokensDef> desc) {
                return filter.contains(desc);
            }
        };

        for (DefDescriptor<TokensDef> descriptor : descriptors) {
            if (filter == null
                    || (filter.contains(descriptor) || Iterables.any(originals.get(descriptor), predicate))) {
                Iterables.addAll(names, definitionService.getDefinition(descriptor).getAllNames());
                names.addAll(dynamicTokens.column(descriptor).keySet());
            }
        }

        return names;
    }

    @Override
    public Optional<String> getDescriptorsUid() {
        if (descriptors.isEmpty()) {
            return Optional.absent();
        }

        Hash.StringBuilder builder = new Hash.StringBuilder();
        for (DefDescriptor<TokensDef> descriptor : descriptors) {
            builder.addString(descriptor.getQualifiedName());
        }
        return Optional.of(builder.build().toString());
    }

    @Override
    public Optional<String> getActiveDynamicTokensUid() {
        if (dynamicTokens.isEmpty()) {
            return Optional.absent();
        }

        Map<String, String> activeDynamicTokens = activeDynamicTokens();

        Hash.StringBuilder builder = new Hash.StringBuilder();
        for (Entry<String, String> entry : activeDynamicTokens.entrySet()) {
            builder.addString(entry.getKey());
            builder.addString(entry.getValue());
        }
        return Optional.of(builder.build().toString());
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this).add("tokens", descriptors).add("dynamicTokens", activeDynamicTokens())
                .toString();
    }
}