001/*
002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved.
003 * 
004 * http://www.izforge.com/izpack/
005 * http://developer.berlios.de/projects/izpack/
006 * 
007 * Copyright 2002 Olexij Tkatchenko
008 * 
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *     http://www.apache.org/licenses/LICENSE-2.0
014 *     
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 */
021
022package com.izforge.izpack.util;
023
024import java.util.ArrayList;
025import java.util.Iterator;
026import java.util.List;
027
028import net.n3.nanoxml.XMLElement;
029
030/**
031 * Encapsulates OS constraints specified on creation time and allows to check them against the
032 * current OS.
033 * 
034 * For example, this is used for <executable>s to check whether the executable is suitable for
035 * the current OS.
036 * 
037 * @author Olexij Tkatchenko <ot@parcs.de>
038 */
039public class OsConstraint implements java.io.Serializable
040{
041
042    /**
043     * 
044     */
045    private static final long serialVersionUID = 3762248660406450488L;
046
047    /** The OS family */
048    private String family;
049
050    /** OS name from java system properties */
051    private String name;
052
053    /** OS version from java system properties */
054    private String version;
055
056    /** OS architecture from java system properties */
057    private String arch;
058
059    /**
060     * Constructs a new instance. Please remember, MacOSX belongs to Unix family.
061     * 
062     * @param family The OS family (unix, windows or mac).
063     * @param name The exact OS name.
064     * @param version The exact OS version (check property <code>os.version</code> for values).
065     * @param arch The machine architecture (check property <code>os.arch</code> for values).
066     */
067    public OsConstraint(String family, String name, String version, String arch)
068    {
069        this.family = family != null ? family.toLowerCase() : null;
070        this.name = name != null ? name.toLowerCase() : null;
071        this.version = version != null ? version.toLowerCase() : null;
072        this.arch = arch != null ? arch.toLowerCase() : null;
073    }
074
075    /**
076     * Matches OS specification in this class against current system properties.
077     * 
078     * @return Description of the Return Value
079     */
080    public boolean matchCurrentSystem()
081    {
082        boolean match = true;
083        String osName = System.getProperty("os.name").toLowerCase();
084
085        if (arch != null && arch.length() != 0)
086        {
087            match = System.getProperty("os.arch").toLowerCase().equals(arch);
088        }
089        if (match && version != null && version.length() != 0)
090        {
091            match = System.getProperty("os.version").toLowerCase().equals(version);
092        }
093        if (match && name != null && name.length() != 0)
094        {
095            match = osName.equals(name);
096        }
097        if (match && family != null)
098        {
099            if (family.equals("windows"))
100            {
101                match = OsVersion.IS_WINDOWS;
102            }
103            else if (family.equals("mac") || family.equals("osx"))
104            {
105                match = OsVersion.IS_OSX;
106            }
107            else if (family.equals("unix"))
108            {
109                match = OsVersion.IS_UNIX;
110            }
111        }
112
113        return match && (family != null || name != null || version != null || arch != null);
114    }
115
116    /**
117     * Extract a list of OS constraints from given element.
118     * 
119     * @param element parent XMLElement
120     * @return List of OsConstraint (or empty List if no constraints found)
121     */
122    static public List getOsList(XMLElement element)
123    {
124        // get os info on this executable
125        ArrayList osList = new ArrayList();
126        Iterator osIterator = element.getChildrenNamed("os").iterator();
127        while (osIterator.hasNext())
128        {
129            XMLElement os = (XMLElement) osIterator.next();
130            osList.add(new OsConstraint(os.getAttribute("family", null), os.getAttribute("name",
131                    null), os.getAttribute("version", null), os.getAttribute("arch", null)));
132        }
133
134        // backward compatibility: still support os attribute
135        String osattr = element.getAttribute("os");
136        if (osattr != null && osattr.length() > 0)
137        {
138            // add the "os" attribute as a family constraint
139            osList.add(new OsConstraint(osattr, null, null, null));
140        }
141
142        return osList;
143    }
144
145    /**
146     * Helper function: Scan a list of OsConstraints for a match.
147     * 
148     * @param constraint_list List of OsConstraint to check
149     * 
150     * @return true if one of the OsConstraints matched the current system or constraint_list is
151     * null (no constraints), false if none of the OsConstraints matched
152     */
153    public static boolean oneMatchesCurrentSystem(List constraint_list)
154    {
155        if (constraint_list == null) return true;
156
157        Iterator constraint_it = constraint_list.iterator();
158
159        // no constraints at all - matches!
160        if (!constraint_it.hasNext()) return true;
161
162        while (constraint_it.hasNext())
163        {
164            OsConstraint osc = (OsConstraint) constraint_it.next();
165
166            Debug.trace("checking if os constraints " + osc + " match current OS");
167
168            // check for match
169            if (osc.matchCurrentSystem())
170            {
171                Debug.trace("matched current OS.");
172                return true; // bail out on first match
173            }
174
175        }
176
177        Debug.trace("no match with current OS!");
178        // no match found
179        return false;
180    }
181
182    /**
183     * Helper function: Check whether the given XMLElement is "suitable" for the current OS.
184     * 
185     * @param el The XMLElement to check for OS constraints.
186     * 
187     * @return true if there were no OS constraints or the constraints matched the current OS.
188     * 
189     */
190    public static boolean oneMatchesCurrentSystem(XMLElement el)
191    {
192        return oneMatchesCurrentSystem(getOsList(el));
193    }
194
195    public void setFamily(String f)
196    {
197        family = f.toLowerCase();
198    }
199
200    public String getFamily()
201    {
202        return family;
203    }
204
205    public void setName(String n)
206    {
207        name = n.toLowerCase();
208    }
209
210    public String getName()
211    {
212        return name;
213    }
214
215    public void setVersion(String v)
216    {
217        version = v.toLowerCase();
218    }
219
220    public String getVersion()
221    {
222        return version;
223    }
224
225    public void setArch(String a)
226    {
227        arch = a.toLowerCase();
228    }
229
230    public String getArch()
231    {
232        return arch;
233    }
234
235    public String toString()
236    {
237        StringBuffer retval = new StringBuffer();
238        retval.append("[Os ");
239        retval.append(" family " + family);
240        retval.append(" name " + name);
241        retval.append(" version " + version);
242        retval.append(" arch " + arch);
243        retval.append(" ]");
244        return retval.toString();
245    }
246
247}