001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.util;
018
019import java.io.File;
020import java.util.ArrayList;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Locale;
024import java.util.Set;
025
026/**
027 * Class to help determining the OS.
028 */
029public final class Os {
030    /**
031     * All Windows based OSes.
032     */
033    public static final OsFamily OS_FAMILY_WINDOWS = new OsFamily("windows");
034
035    /**
036     * All DOS based OSes.
037     */
038    public static final OsFamily OS_FAMILY_DOS = new OsFamily("dos");
039
040    /**
041     * All Windows NT based OSes.
042     */
043    public static final OsFamily OS_FAMILY_WINNT = new OsFamily("nt", new OsFamily[] { OS_FAMILY_WINDOWS });
044
045    /**
046     * All Windows 9x based OSes.
047     */
048    public static final OsFamily OS_FAMILY_WIN9X = new OsFamily("win9x",
049            new OsFamily[] { OS_FAMILY_WINDOWS, OS_FAMILY_DOS });
050
051    /**
052     * OS/2.
053     */
054    public static final OsFamily OS_FAMILY_OS2 = new OsFamily("os/2", new OsFamily[] { OS_FAMILY_DOS });
055
056    /**
057     * Netware.
058     */
059    public static final OsFamily OS_FAMILY_NETWARE = new OsFamily("netware");
060
061    /**
062     * All UNIX based OSes.
063     */
064    public static final OsFamily OS_FAMILY_UNIX = new OsFamily("unix");
065
066    /**
067     * All Mac based OSes.
068     */
069    public static final OsFamily OS_FAMILY_MAC = new OsFamily("mac");
070
071    /**
072     * OSX.
073     */
074    public static final OsFamily OS_FAMILY_OSX = new OsFamily("osx", new OsFamily[] { OS_FAMILY_UNIX, OS_FAMILY_MAC });
075
076    private static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.US);
077    private static final String OS_ARCH = System.getProperty("os.arch").toLowerCase(Locale.US);
078    private static final String OS_VERSION = System.getProperty("os.version").toLowerCase(Locale.US);
079    private static final String PATH_SEP = File.pathSeparator;
080    private static final OsFamily OS_FAMILY;
081    private static final OsFamily[] OS_ALL_FAMILIES;
082
083    private static final OsFamily[] ALL_FAMILIES = new OsFamily[] { OS_FAMILY_DOS, OS_FAMILY_MAC, OS_FAMILY_NETWARE,
084            OS_FAMILY_OS2, OS_FAMILY_OSX, OS_FAMILY_UNIX, OS_FAMILY_WINDOWS, OS_FAMILY_WINNT, OS_FAMILY_WIN9X };
085
086    static {
087        OS_FAMILY = determineOsFamily();
088        OS_ALL_FAMILIES = determineAllFamilies();
089    }
090
091    /**
092     * Private constructor to block instantiation.
093     */
094    private Os() {
095    }
096
097    /**
098     * Determines if the OS on which Ant is executing matches the given OS version.
099     *
100     * @param version The version to check.
101     * @return true if the version matches.
102     */
103    public static boolean isVersion(final String version) {
104        return isOs((OsFamily) null, null, null, version);
105    }
106
107    /**
108     * Determines if the OS on which Ant is executing matches the given OS architecture.
109     *
110     * @param arch The architecture to check.
111     * @return true if the architecture mataches.
112     */
113    public static boolean isArch(final String arch) {
114        return isOs((OsFamily) null, null, arch, null);
115    }
116
117    /**
118     * Determines if the OS on which Ant is executing matches the given OS family.
119     *
120     * @param family The family to check.
121     * @return true if the family matches.
122     */
123    public static boolean isFamily(final String family) {
124        return isOs(family, null, null, null);
125    }
126
127    /**
128     * Determines if the OS on which Ant is executing matches the given OS family.
129     *
130     * @param family The family to check.
131     * @return true if the family matches.
132     */
133    public static boolean isFamily(final OsFamily family) {
134        return isOs(family, null, null, null);
135    }
136
137    /**
138     * Determines if the OS on which Ant is executing matches the given OS name.
139     *
140     * @param name Description of Parameter
141     * @return The Name value
142     * @since 1.7
143     */
144    public static boolean isName(final String name) {
145        return isOs((OsFamily) null, name, null, null);
146    }
147
148    /**
149     * Determines if the OS on which Ant is executing matches the given OS family, name, architecture and version.
150     *
151     * @param family The OS family
152     * @param name The OS name
153     * @param arch The OS architecture
154     * @param version The OS version
155     * @return The Os value
156     */
157    public static boolean isOs(final String family, final String name, final String arch, final String version) {
158        return isOs(getFamily(family), name, arch, version);
159    }
160
161    /**
162     * Determines if the OS on which Ant is executing matches the given OS family, name, architecture and version.
163     *
164     * @param family The OS family
165     * @param name The OS name
166     * @param arch The OS architecture
167     * @param version The OS version
168     * @return The Os value
169     */
170    public static boolean isOs(final OsFamily family, final String name, final String arch, final String version) {
171        if (family != null || name != null || arch != null || version != null) {
172            final boolean isFamily = familyMatches(family);
173            final boolean isName = nameMatches(name);
174            final boolean isArch = archMatches(arch);
175            final boolean isVersion = versionMatches(version);
176
177            return isFamily && isName && isArch && isVersion;
178        }
179        return false;
180    }
181
182    /**
183     * Locates an OsFamily by name (case-insensitive).
184     *
185     * @param name The family name to lookup.
186     * @return the OS family, or null if not found.
187     */
188    public static OsFamily getFamily(final String name) {
189        for (final OsFamily osFamily : ALL_FAMILIES) {
190            if (osFamily.getName().equalsIgnoreCase(name)) {
191                return osFamily;
192            }
193        }
194
195        return null;
196    }
197
198    private static boolean versionMatches(final String version) {
199        boolean isVersion = true;
200        if (version != null) {
201            isVersion = version.equalsIgnoreCase(OS_VERSION);
202        }
203        return isVersion;
204    }
205
206    private static boolean archMatches(final String arch) {
207        boolean isArch = true;
208        if (arch != null) {
209            isArch = arch.equalsIgnoreCase(OS_ARCH);
210        }
211        return isArch;
212    }
213
214    private static boolean nameMatches(final String name) {
215        boolean isName = true;
216        if (name != null) {
217            isName = name.equalsIgnoreCase(OS_NAME);
218        }
219        return isName;
220    }
221
222    private static boolean familyMatches(final OsFamily family) {
223        if (family == null) {
224            return false;
225        }
226        for (final OsFamily osFamily : OS_ALL_FAMILIES) {
227            if (family == osFamily) {
228                return true;
229            }
230        }
231        return false;
232    }
233
234    private static OsFamily[] determineAllFamilies() {
235        // Determine all families the current OS belongs to
236        final Set<OsFamily> allFamilies = new HashSet<>();
237        if (OS_FAMILY != null) {
238            final List<OsFamily> queue = new ArrayList<>();
239            queue.add(OS_FAMILY);
240            while (queue.size() > 0) {
241                final OsFamily family = queue.remove(0);
242                allFamilies.add(family);
243                final OsFamily[] families = family.getFamilies();
244                for (final OsFamily parent : families) {
245                    queue.add(parent);
246                }
247            }
248        }
249        return allFamilies.toArray(new OsFamily[allFamilies.size()]);
250    }
251
252    private static OsFamily determineOsFamily() {
253        // Determine the most specific OS family
254        if (OS_NAME.indexOf("windows") > -1) {
255            if (OS_NAME.indexOf("xp") > -1 || OS_NAME.indexOf("2000") > -1 || OS_NAME.indexOf("nt") > -1) {
256                return OS_FAMILY_WINNT;
257            }
258            return OS_FAMILY_WIN9X;
259        } else if (OS_NAME.indexOf("os/2") > -1) {
260            return OS_FAMILY_OS2;
261        } else if (OS_NAME.indexOf("netware") > -1) {
262            return OS_FAMILY_NETWARE;
263        } else if (OS_NAME.indexOf("mac") > -1) {
264            if (OS_NAME.endsWith("x")) {
265                return OS_FAMILY_OSX;
266            }
267            return OS_FAMILY_MAC;
268        } else if (PATH_SEP.equals(":")) {
269            return OS_FAMILY_UNIX;
270        } else {
271            return null;
272        }
273    }
274}