/* * Copyright 2013 Hewlett-Packard Development Company, L.P * * 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.hp.alm.ali.idea.translate; import com.hp.alm.ali.idea.entity.EntityRef; import com.hp.alm.ali.idea.model.Field; import com.hp.alm.ali.idea.services.EntityService; import com.hp.alm.ali.idea.entity.EntityListener; import com.hp.alm.ali.idea.entity.SimpleCache; import com.hp.alm.ali.idea.services.MetadataService; import com.hp.alm.ali.idea.model.Entity; import com.intellij.openapi.project.Project; import com.intellij.util.ui.UIUtil; import java.text.MessageFormat; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; public class EntityReferenceTranslator implements Translator { private static Map<String, List<String>> map; static { map = new HashMap<String, List<String>>(); map.put("build-instance", Arrays.asList("{1} #{0}", "number", "type.name")); map.put("changeset", Arrays.asList("{0} {1}: {2}", "date", "owner", "description")); } private SimpleCache cache; private String targetType; private String mask; private List<String> fields; private EntityService entityService; private MetadataService metadataService; public EntityReferenceTranslator(Project project, String targetType, SimpleCache cache) { this.cache = cache; this.targetType = targetType; entityService = project.getComponent(EntityService.class); metadataService = project.getComponent(MetadataService.class); List<String> maskAndFields = map.get(targetType); if(maskAndFields == null) { mask = "{0}"; fields = Arrays.asList("name"); } else { mask = maskAndFields.get(0); fields = maskAndFields.subList(1, maskAndFields.size()); } } @Override public String translate(String value, ValueCallback callback) { return new Execution(callback).perform(value); } public String getTargetType() { return targetType; } private class Execution implements EntityListener { private Entity targetEntity; private EntityRef targetRef; private Set<EntityRef> requested; private ValueCallback callback; private Execution(ValueCallback callback) { this.callback = callback; requested = new HashSet<EntityRef>(); } private String perform(String value) { final Set<String> props = new HashSet<String>(); for(String field: fields) { if(field.contains(".")) { props.add(field.substring(0, field.indexOf("."))); } else { props.add(field); } } targetRef = new EntityRef(targetType, Integer.valueOf(value)); targetEntity = cache.lookup(targetRef, props); if(targetEntity != null) { return calculateValue(); } else { if(cache.isNotFound(targetRef)) { return TranslateService.NA_TOKEN; } requested.add(targetRef); entityService.requestCachedEntity(targetRef, new LinkedList<String>(props), this); return null; } } @Override public void entityLoaded(Entity entity, Event event) { cache.add(entity); if(new EntityRef(entity).equals(targetRef)) { targetEntity = entity; } setValue(calculateValue()); } @Override public void entityNotFound(EntityRef ref, boolean removed) { cache.addNotFound(ref); if(ref.equals(targetRef)) { setValue(TranslateService.NA_TOKEN); } else { setValue(calculateValue()); } } private String resolveField(SimpleCache cache, Entity entity, List<String> field) { String value = entity.getPropertyValue(field.get(0)); if(value.isEmpty() || field.size() == 1) { return value; } else { int targetId = Integer.valueOf(value); String targetType = getFieldTarget(entity, field.get(0)); EntityRef targetRef = new EntityRef(targetType, targetId); List<String> props = Arrays.asList(field.get(1)); Entity targetEntity = cache.lookup(targetRef, props); if(targetEntity != null) { return resolveField(cache, targetEntity, field.subList(1, field.size())); } else if(cache.isNotFound(targetRef)) { return TranslateService.NA_TOKEN; } else if(requested.add(targetRef)) { entityService.requestCachedEntity(targetRef, props, this); } return null; } } private String getFieldTarget(Entity entity, String fieldName) { Field field = metadataService.getEntityMetadata(entity.getType()).getField(fieldName); return field.resolveReference(entity); } private String calculateValue() { List<String> values = new LinkedList<String>(); for(String field: fields) { String fieldValue = resolveField(cache, targetEntity, Arrays.asList(field.split("\\."))); if(fieldValue == null) { return null; } values.add(fieldValue); } return MessageFormat.format(mask, values.toArray()); } private void setValue(final String value) { if(value != null) { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { callback.value(value); } }); } } } }