/******************************************************************************* * Copyright (c) 2015 ARM Ltd. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * ARM Ltd and ARM Germany GmbH - Initial API and implementation *******************************************************************************/ package com.arm.cmsis.pack.data; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import com.arm.cmsis.pack.common.CmsisConstants; import com.arm.cmsis.pack.enums.EEvaluationResult; import com.arm.cmsis.pack.enums.EVersionMatchMode; import com.arm.cmsis.pack.generic.IAttributes; import com.arm.cmsis.pack.item.CmsisTreeItem; import com.arm.cmsis.pack.utils.AlnumComparator; import com.arm.cmsis.pack.utils.Utils; /** * Default implementation of ICpItem interface */ public class CpItem extends CmsisTreeItem<ICpItem> implements ICpItem { protected IAttributes fAttributes = new CpAttributes(); protected ICpItem fCondition = null; // cached condition reference for quick access protected String fURL = null; protected String fId = null; /** * Default hierarchy constructor * @param parent parent ICpItem */ public CpItem(ICpItem parent){ super(parent); } /** * Constructs item for the given parent and tag * @param parent parent ICpItem * @param tag item's tag */ public CpItem(ICpItem parent, String tag) { super(parent); setTag(tag); } @Override public IAttributes attributes() { return fAttributes; } @Override public String getAttribute(String key) { // Proxy method to get attribute from attributes return attributes().getAttribute(key, CmsisConstants.EMPTY_STRING); } @Override public boolean hasAttribute(String key) { return attributes().hasAttribute(key); } @Override public synchronized String getId() { if (fId == null) { fId = constructId(); } return fId; } @Override protected String constructName() { if(hasAttribute(CmsisConstants.NAME)) { return getAttribute(CmsisConstants.NAME); } return super.constructName(); } /** * Constructs element Id * default implementation tries to get "id" attribute * if it is not successful, returns <code>"tag.name"<\code> * derived classes may implement other algorithms * @return constructed element Id */ public String constructId() { if(hasAttribute(CmsisConstants.ID)) { return getAttribute(CmsisConstants.ID); } // if not successful, returns "tag.name" String id = getTag(); if(hasAttribute(CmsisConstants.NAME)) { id += ":" + getAttribute(CmsisConstants.NAME); //$NON-NLS-1$ } return id; } @Override public ICpItem getParent(String tag) { for(ICpItem item = getParent(); item != null; item = item.getParent()) { if(item.getTag().equals(tag)) { return item; } } return null; } @Override public ICpComponent getParentComponent() { if(getParent() != null) { return getParent().getParentComponent(); } return null; } @Override public ICpPack getPack() { if(getParent() != null) { return getParent().getPack(); } return null; } @Override public ICpRootItem getRootItem() { if(getParent() != null) { return getParent().getRootItem(); } return null; } @Override public String getRootDir(boolean keepSlash) { ICpRootItem root = getRootItem(); if(root != null) return root.getDir(keepSlash); return null; } @Override public String getRootFileName() { ICpRootItem root = getRootItem(); if(root != null) return root.getFileName(); return null; } @Override public String getPackId() { ICpPack pack = getPack(); if(pack != null) { return pack.getId(); } return CmsisConstants.EMPTY_STRING; } @Override public String getPackFamilyId() { ICpPack pack = getPack(); if(pack != null) { return pack.getPackFamilyId(); } return CmsisConstants.EMPTY_STRING; } @Override public String getItemKey(ICpItem item) { if(item != null) { return item.getTag(); } return null; } @Override public ICpItem getProperty(String id) { Collection<? extends ICpItem> children = getChildren(); if(children != null) { for(ICpItem item : children){ if(item.getId().equals(id)) { return item; } } } return null; } @Override public Collection<? extends ICpItem> getGrandChildren(String tag) { ICpItem child = getFirstChild(tag); if(child != null) { return child.getChildren(); } return null; } @Override public Collection<ICpItem> getChildren(String tag) { List<ICpItem> tagChildren = new LinkedList<ICpItem>(); Collection<? extends ICpItem> children = getChildren(); if(children != null) { for(ICpItem item: children) { if(item.getTag().equals(tag)) { tagChildren.add(item); } } } return tagChildren; } @Override protected List<ICpItem> children() { return (List<ICpItem>)super.children(); } @Override public ICpItem createItem(ICpItem parent, String tag) { ICpItem item = createChildItem(tag); return item; } /** * Creates an item depending on its tag * @param tag child's XML tag * @return */ protected ICpItem createChildItem(String tag) { switch(tag) { case CmsisConstants.CONDITION: return new CpCondition(this, tag); case CmsisConstants.API_TAG: case CmsisConstants.COMPONENT_TAG: return new CpComponent(this, tag); case CmsisConstants.BOARD_TAG: return new CpBoard(this, tag); case CmsisConstants.FILE_TAG: return new CpFile(this, tag); case CmsisConstants.DEVICES_TAG: return new CpDeviceItemContainer(this, tag); case CmsisConstants.TAXONOMY_TAG: return new CpTaxonomyContainer(this, tag); case CmsisConstants.EXAMPLE_TAG: return new CpExample(this, tag); case CmsisConstants.BUNDLE_TAG: return new CpItem(this, tag); case CmsisConstants.GENERATOR_TAG: return new CpGenerator(this, tag); default: break; } return new CpItem(this, tag); } @Override public boolean hasCondition() { return hasAttribute(CmsisConstants.CONDITION); } @Override public String getConditionId() { return getAttribute(CmsisConstants.CONDITION); } @Override public synchronized ICpItem getCondition() { if(fCondition == null) { // not cached yet String conditionID = getConditionId(); if(conditionID != null && !conditionID.isEmpty()) { ICpPack pack = getPack(); if(pack != null) { fCondition = pack.getCondition(conditionID); } } } return fCondition; } @Override public boolean isDeviceDependent() { if(attributes().getAttributeAsBoolean(CmsisConstants.DEVICE_DEPENDENT, false)) { return true; } ICpItem condition = getCondition(); if(condition != null) { return condition.isDeviceDependent(); } return false; } @Override public EEvaluationResult evaluate(ICpConditionContext context) { ICpItem condition = getCondition(); if(condition != null) { return context.evaluate(condition); } return EEvaluationResult.IGNORED; } @Override public String getEffectiveAttribute(final String key) { if(hasAttribute(key)) { return getAttribute(key); } ICpItem effectiveParent = getEffectiveParent(); if(effectiveParent != null) { return effectiveParent.getEffectiveAttribute(key); } return null; } @Override public Map<String, String> getEffectiveAttributes(Map<String, String> m) { if(m == null) { m = new HashMap<String, String>(); } Map<String, String> attributesMap = attributes().getAttributesAsMap(); if(attributesMap != null) { for(Entry<String, String> e: attributesMap.entrySet()) { String key = e.getKey(); if(!m.containsKey(key)) { m.put(key, e.getValue()); } } } ICpItem effectiveParent = getEffectiveParent(); if(effectiveParent != null) { effectiveParent.getEffectiveAttributes(m); return m; } return m; } @Override public void mergeProperty(ICpItem p, String processorName) { String id = p.getId(); ICpItem inserted = getProperty(id); if(p == inserted) return; // do not insert the same item twice (can happen when merging effective content) if(inserted == null || !p.isUnique()) { addChild(p); // insert only unique properties or descriptions if(p.providesEffectiveContent()) { p.mergeEffectiveContent(p, processorName); } } else { // add missing attributes, but do not replace existing ones (we go down-up) // process sub-properties as well inserted.mergeEffectiveContent(p, processorName); } } /** * Searches supplied list for a property with given ID * @param id property id to find * @param props list of properties * @return device property if found, null otherwise */ public static ICpItem getItemFromList(String id, List<ICpItem> props) { for(ICpItem p : props){ if(p.getId().equals(id)) { return p; } } return null; } @Override public void mergeEffectiveContent(ICpItem property, String processorName) { attributes().mergeAttributes(property.attributes()); // always merge attributes } @Override public boolean providesEffectiveContent() { return false; // default returns false } @Override public boolean isUnique() { return false; // default is false } @Override public boolean isGenerated() { ICpItem parent = getParent(); if(parent != null) return parent.isGenerated(); return false; } @Override public boolean isDeprecated() { ICpPack pack = getPack(); if(pack != null) return pack.isDeprecated(); return false; } @Override public ICpItem getEffectiveContent() { return null; } @Override public String getVendor() { String vendor = null; if(hasAttribute(CmsisConstants.DVENDOR)) { vendor = getAttribute(CmsisConstants.DVENDOR); } else if(hasAttribute(CmsisConstants.VENDOR)) { return getAttribute(CmsisConstants.VENDOR); } if(vendor != null && !vendor.isEmpty()) { return vendor; } ICpItem parent = getParent(); if(parent != null) { return parent.getVendor(); } return null; } @Override public String getVersion() { if(hasAttribute(CmsisConstants.VERSION)) { return getAttribute(CmsisConstants.VERSION); } ICpItem parent = getParent(); if(parent != null) { return parent.getVersion(); } return null; } @Override public String getDescription() { ICpItem descr = getFirstChild(CmsisConstants.DESCRIPTION); if(descr != null) { return descr.getText(); } return CmsisConstants.EMPTY_STRING; } @Override public synchronized String getUrl() { if(fURL == null) { String url = getAttribute(CmsisConstants.URL); if(url == null || url.isEmpty()) { ICpItem urlItem = getFirstChild(CmsisConstants.URL); if(urlItem != null) { url = urlItem.getText(); } } if(url == null || url.isEmpty()) { fURL = getDoc(); } else { fURL = getAbsolutePath(url); } } return fURL; } @Override public String getAbsolutePath(String relPath) { if(relPath == null || relPath.isEmpty()) { return CmsisConstants.EMPTY_STRING; } if(relPath.startsWith("\\\\") || relPath.indexOf(":") == 1) { // Windows only: share or absolute with drive letter //$NON-NLS-1$ //$NON-NLS-2$ return relPath; // already absolute (windows) } // check if path is already absolute or is an URL // absolute url without http: // http: or https: or file: if (relPath.startsWith("//") || relPath.startsWith("www.") || relPath.indexOf(':') != -1 ) { //$NON-NLS-1$ //$NON-NLS-2$ return relPath; // an URL => already absolute } // relative path => add pack installation directory String basePath = getRootDir(true); if(basePath != null && !basePath.isEmpty()) { String absPath = basePath + relPath; IPath path = new Path(absPath); return path.toString(); } return relPath; } @Override public String getDoc() { String doc = getAttribute(CmsisConstants.DOC); if(doc == null || doc.isEmpty()) { doc = getAttribute(CmsisConstants.NAME); } if(doc == null || doc.isEmpty()) { ICpItem docItem = getFirstChild(CmsisConstants.DOC); if(docItem != null) { doc = docItem.getText(); } } return getAbsolutePath(doc); } @Override public String getProcessorName() { return getProcessorName(attributes()); } @Override public int getPunitIndex() { return getPunitIndex(attributes()); } @Override public int getPunitsCount() { return getPunitsCount(attributes()); } /** * Returns "Pname" attribute of the element representing device property * @param attributes attributes to extract processor name * @return processor name or empty string if "pname" attribute not found */ static public String getProcessorName(IAttributes attributes) { return attributes.getAttribute(CmsisConstants.PNAME, CmsisConstants.EMPTY_STRING); } /** * Returns "Punit" attribute as integer * @param attributes attributes to extract Punit * @return processor unit index (0 is default) */ static public int getPunitIndex(IAttributes attributes) { return attributes.getAttributeAsInt(CmsisConstants.PUNIT, 0); } /** * Returns "Punits" attribute as integer * @param attributes attributes to extract "Punits" * @return processor unit count (1 is default) */ static public int getPunitsCount(IAttributes attributes) { return attributes.getAttributeAsInt(CmsisConstants.PUNITS, 1); } @Override public String getDeviceName() { return getDeviceName(attributes()); } /** * Returns full device name in form "Name:Pname" * @param attributes attributes to construct full device name * @return full device name or null if the attributes parameter does not represent device */ static public String getDeviceName(IAttributes attributes) { String deviceName = null; if(attributes.hasAttribute(CmsisConstants.DVARIANT)) { deviceName = attributes.getAttribute(CmsisConstants.DVARIANT); } else if(attributes.hasAttribute(CmsisConstants.DNAME)) { deviceName = attributes.getAttribute(CmsisConstants.DNAME); } if(deviceName != null) { String processorName = getProcessorName(attributes); if(!processorName.isEmpty()) { deviceName += ":" + processorName; //$NON-NLS-1$ } } return deviceName; } @Override public String getBundleName() { return getAttribute(CmsisConstants.CBUNDLE); } @Override public EVersionMatchMode getVersionMatchMode() { return EVersionMatchMode.fromString(getAttribute(CmsisConstants.VERSION_MODE)); } @Override public void setVersionMatchMode(EVersionMatchMode mode) { String strValue = EVersionMatchMode.toString(mode); attributes().setAttribute(CmsisConstants.VERSION_MODE, strValue); } @Override public boolean isVersionFixed() { return getVersionMatchMode() == EVersionMatchMode.FIXED; } @Override public Collection<ICpItem> getBooks() { Map<String, ICpItem> books = new TreeMap<String, ICpItem>(new AlnumComparator(false, false)); Collection<? extends ICpItem> children = getChildren(); if(children != null && ! children.isEmpty()) { for(ICpItem book : children) { if(!book.getTag().equals(CmsisConstants.BOOK_TAG)) { continue; } String doc = book.getDoc(); if(doc == null || doc.isEmpty() || books.containsKey(doc)) { continue; } String title = book.getAttribute(CmsisConstants.TITLE); books.put(title, book); } } return books.values(); } @Override public boolean isDefaultVariant() { return attributes().getAttributeAsBoolean(CmsisConstants.IS_DEFAULT_VARIANT, false); } @Override public boolean matchesHost() { String host = getAttribute(CmsisConstants.HOST); return host == null || host.isEmpty() || host.equals(CmsisConstants.ALL) || host.equals(Utils.getHostType()); } }