Path: blob/master/sourcetools/objectmodel/com/ibm/j9tools/om/BuildSpec.java
6004 views
/*******************************************************************************1* Copyright (c) 2007, 2019 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/21package com.ibm.j9tools.om;2223import java.io.File;24import java.io.PrintStream;25import java.text.MessageFormat;26import java.util.Collection;27import java.util.Collections;28import java.util.HashMap;29import java.util.HashSet;30import java.util.Map;31import java.util.Set;32import java.util.TreeMap;3334/**35* The {@link BuildSpec} class describes the details of a J9 specification. It defines the flags,36* sources, and featuers which make up the specification as well as any other relevant information.37*38* @author Maciek Klimkowski39* @author Gabriel Castro40*/41public class BuildSpec extends OMObject implements IFlagContainer, ISourceContainer, Comparable<BuildSpec> {42private String id = null; /* !< build spec id */43private String name = null; /* !< build spec name */44private String runtime = null;45private String cpuArchitecture = null;46private String os = null;47private DefaultSizes defaultSizes = null;48private AsmBuilder asmBuilder = null;49private JclConfiguration jclConfiguration = null;50private int priority = -1;5152private final Map<String, Feature> features = new TreeMap<String, Feature>();53private final Map<String, Flag> flags = new TreeMap<String, Flag>();54private final Map<String, Owner> owners = new TreeMap<String, Owner>();55private final Map<String, Source> sources = new TreeMap<String, Source>();56private final Map<String, Property> properties = new TreeMap<String, Property>();5758/**59* Retrieves the specification ID from the given file name. The file name must have the60* specification file extension {@link ConfigDirectory#BUILD_SPEC_FILE_EXTENSION}.61*62* @param filename the specification file63* @return the spec ID or <code>null</code> if the filename is not identified as a spec file64*/65public static String getIDFromFileName(String filename) {66if (filename != null && filename.endsWith(ConfigDirectory.BUILD_SPEC_FILE_EXTENSION)) {67return filename.substring(filename.lastIndexOf(File.separator) + 1, filename.length() - (ConfigDirectory.BUILD_SPEC_FILE_EXTENSION.length()));68}6970return null;71}7273/**74* Adds a spec owner to this build spec.75*76* @param owner one of the owners of this build spec77*/78public void addOwner(Owner owner) {79owners.put(owner.getId(), owner);80}8182/**83* Retrieves the owner of this build spec for the given owner ID.84*85* @param ownerId the ID of the owner86* @return Owner instance identified by ownerId87*/88public Owner getOwner(String ownerId) {89return owners.get(ownerId);90}9192public Map<String, Owner> getOwners() {93return Collections.unmodifiableMap(owners);94}9596/**97* Retrieves a set of owner IDs defined for this build spec.98*99* @return a Set<String> of owner ids100*/101public Set<String> getOwnerIds() {102return owners.keySet();103}104105/**106* Removes the given owner from this build spec.107*108* @param owner the owner to be remove109*/110public void removeOwner(Owner owner) {111owners.remove(owner.getId());112}113114/**115* Removes the owner with the given ID from this build spec.116*117* @param ownerId the ID of the owner to be removed118*/119public void removeOwner(String ownerId) {120owners.remove(ownerId);121}122123/**124* @see com.ibm.j9tools.om.IFlagContainer#addFlag(com.ibm.j9tools.om.Flag)125*/126public void addFlag(Flag flag) {127flags.put(flag.getId(), flag);128}129130/**131* @see com.ibm.j9tools.om.IFlagContainer#getFlag(java.lang.String)132*/133public Flag getFlag(String flagId) {134if (flags.containsKey(flagId)) {135return flags.get(flagId);136}137138for (Feature feature : features.values()) {139if (feature.hasFlag(flagId)) {140return feature.getFlag(flagId);141}142}143144return null;145}146147/**148* Returns a local Flag149* @param flagId ID of the Flag that needs to be returned150* @return Flag The Flag that is wanted, or <code>null</code> if the Flag does not exist151*/152public Flag getLocalFlag(String flagId) {153return flags.get(flagId);154}155156/**157* @see com.ibm.j9tools.om.IFlagContainer#getFlags()158*/159public Map<String, Flag> getFlags() {160Map<String, Flag> allFlags = new TreeMap<String, Flag>();161allFlags.putAll(flags);162163for (Feature feature : features.values()) {164allFlags.putAll(feature.getFlags());165}166167return Collections.unmodifiableMap(allFlags);168}169170/**171* @see com.ibm.j9tools.om.IFlagContainer#getFlags(java.lang.String)172*/173public Map<String, Flag> getFlags(String category) {174Map<String, Flag> allFlags = new TreeMap<String, Flag>();175176for (Flag flag : getFlags().values()) {177if (flag.getCategory().equals(category)) {178allFlags.put(flag.getId(), flag);179}180}181182return Collections.unmodifiableMap(allFlags);183}184185/**186* Retrieves only the flags that were defined in this build spec. This does not include187* any flags defined in this J9 specification's features.188*189* @return a {@link Map} of the local flags190*/191public Map<String, Flag> getLocalFlags() {192return Collections.unmodifiableMap(flags);193}194195/**196* @see com.ibm.j9tools.om.IFlagContainer#getLocalFlags(java.lang.String)197*/198public Map<String, Flag> getLocalFlags(String category) {199Map<String, Flag> allFlags = new TreeMap<String, Flag>();200201for (Flag flag : flags.values()) {202if (flag.getCategory().equals(category)) {203allFlags.put(flag.getId(), flag);204}205}206207return Collections.unmodifiableMap(allFlags);208}209210/**211* Checks for existence of a flag. Not to be confused with the value of a flag.212*213* @param flagId ID of the flag to check for214* @return <code>true</code> if the flag is included for this spec, <code>false</code> otherwise215*/216public boolean hasFlag(String flagId) {217if (flags.containsKey(flagId)) {218return true;219}220221// Check if one of the features has the flag222for (Feature feature : features.values()) {223if (feature.hasFlag(flagId)) {224return true;225}226}227228return false;229}230231/**232* Checks for the existence of a local flag.233*234* @param flagId ID of the flag to check for235* @return <code>true</code> if the flag is included for this spec, <code>false</code> otherwise236*/237public boolean hasLocalFlag(String flagId) {238return flags.containsKey(flagId);239}240241/**242* @see com.ibm.j9tools.om.IFlagContainer#removeFlag(com.ibm.j9tools.om.Flag)243*/244public void removeFlag(Flag flag) {245flags.remove(flag.getId());246}247248/**249* @see com.ibm.j9tools.om.IFlagContainer#removeFlag(java.lang.String)250*/251public void removeFlag(String flagId) {252flags.remove(flagId);253}254255/**256* Adds a fully initialized feature to the build spec. Non-conflicting flags are removed from the local257* list since they're contributed to the build spec by the feature. Sources also found in the feature258* are removed from the build spec.259*260* @param feature loaded instance of Feature261*/262public void addFeature(Feature feature) {263addFeature(feature, false);264}265266/**267* Adds a fully initialized feature to the build spec. Non-conflicting flags are removed from the local268* list since they're contributed to the build spec by the feature. Sources also found in the feature269* are removed from the build spec.270*271* @param feature loaded instance of Feature272* @param overwrite when <code>true</code> overwrites all flags regardless of conflict273*/274public void addFeature(Feature feature, boolean overwrite) {275features.put(feature.getId(), feature);276277// Remove sources already found in the in feature278sources.values().removeAll(feature.getSources().values());279280for (Flag featureFlag : feature.getFlags().values()) {281Flag localFlag = flags.get(featureFlag.getId());282283if (overwrite || (localFlag != null && localFlag.equals(featureFlag))) {284flags.remove(featureFlag.getId());285}286}287}288289/**290* Removes the given feature from this build spec.291*292* @param feature the feature to be removed293*/294public Feature removeFeature(Feature feature) {295return features.remove(feature.getId());296}297298/**299* Removes the feature with the given ID from this build spec.300*301* @param featureId the ID of the feature to be removed302*/303public Feature removeFeature(String featureId) {304return features.remove(featureId);305}306307/**308* Removes the given feature from this build spec and returns its inherited sources309* and flags to the build spec.310*311* @param feature the feature to be removed312*/313public void unbundleFeature(Feature feature) {314Feature localFeature = features.remove(feature.getId());315316if (localFeature != null) {317for (Source source : localFeature.getSources().values()) {318addSource(source);319}320321for (Flag flag : localFeature.getFlags().values()) {322addFlag(flag);323}324}325}326327/**328* Removes the feature with the given ID from this build spec and returns its inherited sources329* and flags to the build spec.330*331* @param featureId the ID of the feature to be removed332*/333public void unbundleFeature(String featureId) {334Feature localFeature = features.remove(featureId);335336if (localFeature != null) {337for (Source source : localFeature.getSources().values()) {338addSource(source);339}340341for (Flag flag : localFeature.getFlags().values()) {342addFlag(flag);343}344}345}346347/**348* Retrieves a set of features defined for this build spec349*350* @return a Collection<Feature>.351*/352public Map<String, Feature> getFeatures() {353return Collections.unmodifiableMap(features);354}355356/**357* Retrieves a Feature identified by the featureId parameter358*359* @param featureId Feature to Retrieves from the build spec360* @return a Feature361*/362public Feature getFeature(String featureId) {363return features.get(featureId);364}365366/**367* Checks for existence of a feature.368*369* @param featureId ID of the feature to check for370* @return <code>true</code> if the feature is included for this spec, <code>false</code> otherwise371*/372public boolean hasFeature(String featureId) {373return features.containsKey(featureId);374}375376/**377* Retrieves the set of sources defined for in build spec.378*379* @return a {@link Map} of all the sources380*/381public Map<String, Source> getSources() {382Map<String, Source> allSources = new TreeMap<String, Source>();383allSources.putAll(sources);384385for (Feature feature : features.values()) {386allSources.putAll(feature.getSources());387}388389return Collections.unmodifiableMap(allSources);390}391392/**393* Retrieves all the local sources for this build spec. This does not include sources394* defined in included features.395*396* @return a {@link Map} of the local sources397*/398public Map<String, Source> getLocalSources() {399return Collections.unmodifiableMap(sources);400}401402/**403* Retrieves a source module definition404*405* @param sourceId The ID of the source module406* @return the requested source407*/408public Source getSource(String sourceId) {409if (sources.containsKey(sourceId)) {410return sources.get(sourceId);411}412413for (Feature feature : features.values()) {414if (feature.hasSource(sourceId)) {415return feature.getSource(sourceId);416}417}418419return null;420}421422/**423* Retrieves a source module definition that is local to this container424*425* @param sourceId The ID of the source module426* @return the requested source427*/428public Source getLocalSource(String sourceId) {429return sources.get(sourceId);430}431432/**433* Adds the given source to this build spec.434*435* @param source the source to be added436*/437public void addSource(Source source) {438sources.put(source.getId(), source);439}440441/**442* Removes the given source from this build spec.443*444* @param source the source to be removed445*/446public void removeSource(Source source) {447sources.remove(source.getId());448}449450/**451* Removes the source with the given source ID from this build spec.452*453* @param sourceId the ID of the source454*/455public void removeSource(String sourceId) {456sources.remove(sourceId);457}458459/**460* Checks for existence of a source.461*462* @param sourceId ID of the source to check for463* @return <code>true</code> if the source is included for this spec, <code>false</code> otherwise464*/465public boolean hasSource(String sourceId) {466if (sources.containsKey(sourceId)) {467return true;468}469470// Check if one of the features has the flag471for (Feature feature : features.values()) {472if (feature.hasSource(sourceId)) {473return true;474}475}476477return false;478}479480/**481* Checks for existence of a local source.482*483* @param sourceId ID of the source to check for484* @return <code>true</code> if the source is included for this container, <code>false</code> otherwise485*/486public boolean hasLocalSource(String sourceId) {487return sources.containsKey(sourceId);488}489490/**491* Retrieves the set of properties defined for this build spec.492*493* @return a Collection<Property>494*/495public Map<String, Property> getProperties() {496return Collections.unmodifiableMap(properties);497}498499/**500* Retrieves a Property matching given ID501*502* @param propertyId The ID of the property503* @return a Property504*/505public Property getProperty(String propertyId) {506return properties.get(propertyId);507}508509/**510* Adds the given property to this build spec.511*512* @param property the property to be added513*/514public void addProperty(Property property) {515properties.put(property.getName(), property);516}517518/**519* Removes the given property from this build spec.520*521* @param property the property to be removed522*/523public void removeProperty(Property property) {524properties.remove(property.getName());525}526527/**528* Removes the property with the given ID from this build spec.529*530* @param propertyId the property ID531*/532public void removeProperty(String propertyId) {533properties.remove(propertyId);534}535536/**537* Retrieves the assembly builder defined in this build spec.538*539* @return the name assembly builder540*/541public AsmBuilder getAsmBuilder() {542return asmBuilder;543}544545/**546* Sets the name of the assembly builder for this build spec.547*548* @param asmBuilder the assembly builder549*/550public void setAsmBuilder(AsmBuilder asmBuilder) {551this.asmBuilder = asmBuilder;552}553554/**555* Retrieves the name of the CPU architecture defined for this build spec.556*557* @return the name of the CPU architecture558*/559public String getCpuArchitecture() {560return cpuArchitecture;561}562563/**564* Sets the name of the CPU architecture for this build spec.565* @param cpuArchitecture566*/567public void setCpuArchitecture(String cpuArchitecture) {568this.cpuArchitecture = cpuArchitecture;569}570571/**572* Retries the name of the default JCL configuration for this build spec.573*574* @return the name of the default JCL configuration575*/576public JclConfiguration getDefaultJCL() {577return jclConfiguration;578}579580/**581* Sets the name of the default JCL configuration for this build spec.582*583* @param jclConfiguration the default JCL configuration584*/585public void setDefaultJCL(JclConfiguration jclConfiguration) {586this.jclConfiguration = jclConfiguration;587}588589/**590* Retrieves the default size for this build spec.591*592* @return the default size593*/594public DefaultSizes getDefaultSizes() {595return defaultSizes;596}597598/**599* Sets the default size for this build spec.600*601* @param defaultSizes the default size602*/603public void setDefaultSizes(DefaultSizes defaultSizes) {604this.defaultSizes = defaultSizes;605}606607/**608* Retrieves this J9 specification's ID.609*610* @return the ID611*/612public String getId() {613return id;614}615616public String getIdFromFile() {617return getIDFromFileName(getLocation().getFileName());618}619620/**621* Sets this J9 specification's ID.622*623* @param id the build spec ID624*/625public void setId(String id) {626this.id = id;627}628629/**630* Retrieves this J9 specification's name.631*632* @return the name633*/634public String getName() {635return name;636}637638/**639* Retrieves this J9 specification's unique name. If the runtime is available the unique name640* consists of the runtime and the specification id; otherwise, only the ID is returned.641*642* @return the unique specification name643*/644public String getUniqueName() {645if (runtime != null) {646return runtime + ":" + id; //$NON-NLS-1$647}648649return getId();650}651652/**653* Sets this J9 specification's name.654*655* @param name the name656*/657public void setName(String name) {658this.name = name;659}660661/**662* Returns the runtime to which this build spec belongs663*664* @return the runtime name665*/666public String getRuntime() {667return runtime;668}669670/**671* Sets the runtime to which this build spec belongs.672*673* @param runtime the new runtime674*/675protected void setRuntime(String runtime) {676if (runtime != null) {677this.runtime = runtime;678}679}680681/**682* Retrieves the operating system for this build spec.683*684* @return the operating system name685*/686public String getOs() {687return os;688}689690/**691* Sets the name of the operating system for this build spec.692*693* @param os operating system name694*/695public void setOs(String os) {696this.os = os;697}698699/**700* Retrieves the priority for this build spec.701*702* @return the priority value703*/704public int getPriority() {705return priority;706}707708/**709* Sets the priority for this build spec.710*711* @param priority the priority value712*/713public void setPriority(int priority) {714this.priority = priority;715}716717/**718* Verifies the validity of this {@link BuildSpec}'s assembly builders, JCL profiles, sources and flags.719*720* For ASM builders, JCL profiles, and sources validity implies those being defined in the runtime's721* {@link BuildInfo}. Source verification is done by a {@link SourceVerifier}.722*723* Flag verification is done by a {@link FlagVerifier}.724*725* @param flagDefinitions the runtime's flag definitions726* @param buildInfo the runtime's build information727*728* @throws InvalidBuildSpecException thrown when ASMBuilder, JCL, source, or flag errors are found729*/730public void verify(FlagDefinitions flagDefinitions, BuildInfo buildInfo) throws InvalidBuildSpecException {731Collection<Throwable> errors = new HashSet<Throwable>();732733Map<String, Property> featureProperties = new HashMap<String, Property>();734Map<String, Flag> featureFlags = new HashMap<String, Flag>();735Map<String, Source> featureSources = new HashMap<String, Source>();736737String idFromFile = getIDFromFileName(getLocation().getFileName());738739if (!id.equalsIgnoreCase(idFromFile)) {740errors.add(new InvalidSpecIDException(Messages.getString("BuildSpec.specIDAndFilenameNotEqual"), this)); //$NON-NLS-1$741}742743if (buildInfo == null || !buildInfo.getASMBuilders().contains(asmBuilder.getId())) {744errors.add(new InvalidAsmBuilderException(MessageFormat.format(Messages.getString("BuildSpec.invalidASM"), new Object[] { asmBuilder.getId() }), asmBuilder)); //$NON-NLS-1$745}746747if (buildInfo == null || !buildInfo.getJCLs().contains(jclConfiguration.getId())) {748errors.add(new InvalidJCLException(MessageFormat.format(Messages.getString("BuildSpec.invalidJCL"), new Object[] { jclConfiguration.getId() }), jclConfiguration)); //$NON-NLS-1$749}750751if (buildInfo == null || (buildInfo.validateDefaultSizes() && !buildInfo.getDefaultSizes().containsKey(defaultSizes.getId()))) {752errors.add(new InvalidDefaultSizesException(MessageFormat.format(Messages.getString("BuildSpec.invalidDefaultSize"), new Object[] { defaultSizes.getId() }), defaultSizes)); //$NON-NLS-1$753}754755for (Feature feature : features.values()) {756if (feature.isComplete()) {757featureProperties.putAll(feature.getProperties());758featureFlags.putAll(feature.getFlags());759featureSources.putAll(feature.getSources());760} else {761errors.add(new InvalidFeatureException(MessageFormat.format(Messages.getString("BuildSpec.invalidFeature"), new Object[] { feature.getId() }), feature)); //$NON-NLS-1$762}763}764765// Check that properties defined in features are set properly766for (Property property : featureProperties.values()) {767if (!properties.containsKey(property.getName())) {768errors.add(new MissingPropertyException(property, this.getLocation().getFileName()));769}770}771772// Check for local flags that are already defined in feature773for (Flag flag : getLocalFlags().values()) {774if (featureFlags.containsKey(flag.getId())) {775errors.add(new InvalidFlagException(MessageFormat.format(Messages.getString("BuildSpec.invalidFlag"), new Object[] { flag.getId() }), flag)); //$NON-NLS-1$776}777}778779// Check for local sources that are already defined in feature780for (Source source : getLocalSources().values()) {781if (featureSources.containsKey(source.getId())) {782errors.add(new InvalidSourceException(MessageFormat.format(Messages.getString("BuildSpec.invalidSource"), new Object[] { source.getId() }), source)); //$NON-NLS-1$783}784}785786// Verify sources for existence in Build Info definition787SourceVerifier sourceVerifier = (buildInfo == null) ? new SourceVerifier(this, new HashSet<String>()) : new SourceVerifier(this, buildInfo.getSources());788errors.addAll(sourceVerifier.verify());789790// Verify the validity of all flags791FlagVerifier flagVerifier = new FlagVerifier(this, flagDefinitions);792errors.addAll(flagVerifier.verify());793794if (errors.size() > 0) {795throw new InvalidBuildSpecException(errors, this);796}797}798799/**800* Debug helper used to dump this spec's member variables and lists801*802* @param out output stream to print to803* @param prefix prefix to prepend to each line804* @param indentLevel number of spaces to append to the prefix805*/806public void dump(PrintStream out, String prefix, int indentLevel) {807StringBuffer indent = new StringBuffer(prefix);808for (int i = 0; i < indentLevel; i++) {809indent.append(' ');810}811812out.println(indent + "Spec: " + this.getId()); //$NON-NLS-1$813out.println(indent + " |--- name: " + this.getName()); //$NON-NLS-1$814out.println(indent + " |--- asmBuilderName: " + this.getAsmBuilder().getId()); //$NON-NLS-1$815out.println(indent + " |--- cpuArchitecture: " + this.getCpuArchitecture()); //$NON-NLS-1$816out.println(indent + " |--- os: " + this.getOs()); //$NON-NLS-1$817out.println(indent + " |--- defaultJCL: " + this.getDefaultJCL().getId()); //$NON-NLS-1$818out.println(indent + " |--- defaultSizes: " + this.getDefaultSizes()); //$NON-NLS-1$819out.println(indent + " |--- priority: " + this.getPriority()); //$NON-NLS-1$820821out.println(indent + " |"); //$NON-NLS-1$822out.println(indent + " |--- Features "); //$NON-NLS-1$823for (Feature f : getFeatures().values()) {824out.println(indent + " | |-- Feature"); //$NON-NLS-1$825out.println(indent + " | | |- id: " + f.getId()); //$NON-NLS-1$826out.println(indent + " | | +- is complete: " + f.isComplete()); //$NON-NLS-1$827}828829out.println(indent + " |"); //$NON-NLS-1$830out.println(indent + " |--- Flags "); //$NON-NLS-1$831for (Flag f : getFlags().values()) {832out.println(indent + " | |-- Flag"); //$NON-NLS-1$833out.println(indent + " | | +-- id: " + f.getId()); //$NON-NLS-1$834out.println(indent + " | | +-- state: " + f.getState()); //$NON-NLS-1$835}836837out.println(indent + " |"); //$NON-NLS-1$838out.println(indent + " |--- Sources "); //$NON-NLS-1$839for (Source s : getSources().values()) {840out.println(indent + " | |-- source"); //$NON-NLS-1$841out.println(indent + " | | +-- id: " + s.getId()); //$NON-NLS-1$842}843844}845846/**847* Compares this build spec to another build spec for ordering. This ordering848* is based on the build spec ID and its runtime (if one is set).849*850* @see java.lang.Comparable#compareTo(java.lang.Object)851*/852public int compareTo(BuildSpec buildSpec) {853int idCompareResult = id.compareTo(buildSpec.id);854855if (idCompareResult == 0 && runtime != null && buildSpec.getRuntime() != null) {856return runtime.compareTo(buildSpec.getRuntime());857}858859return idCompareResult;860}861862/**863* @see java.lang.Object#toString()864*/865@Override866public String toString() {867StringBuilder sb = new StringBuilder();868if (runtime != null) {869sb.append(runtime);870sb.append(":"); //$NON-NLS-1$871}872sb.append(id);873874return sb.toString();875}876877/**878* @see java.lang.Object#equals(java.lang.Object)879*/880@Override881public boolean equals(Object o) {882if (o instanceof BuildSpec) {883BuildSpec spec = (BuildSpec) o;884if (runtime != null && spec.getRuntime() != null) {885return runtime.equals(spec.getRuntime()) && name.equals(spec.getName()) && id.equals(spec.getId());886}887888return name.equals(spec.getName()) && id.equals(spec.getId());889}890891return false;892}893894}895896897