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.wicket.util.lang;
018
019import org.apache.wicket.util.string.StringList;
020
021/**
022 * Utilities for dealing with packages.
023 * 
024 * @author Jonathan Locke
025 * @author Niclas Hedhman
026 */
027public final class Packages
028{
029        /**
030         * Takes a package and a path to a resource and returns an absolute path to the resource.
031         * <p>
032         * See {@link #absolutePath(String, String)} for details.
033         * 
034         * @param p
035         *            The package to start at
036         * @param path
037         *            The path to the resource
038         * @return The absolute path
039         */
040        public static String absolutePath(final Class<?> p, final String path)
041        {
042                String packName = (p != null ? extractPackageName(p) : "");
043                return absolutePath(packName, path);
044        }
045
046        /**
047         * Takes a package and a path to a resource and returns an absolute path to the resource.
048         * <p>
049         * See {@link #absolutePath(String, String)} for details.
050         * 
051         * @param p
052         *            The package to start at
053         * @param relativePath
054         *            The path to the resource
055         * @return The absolute path
056         */
057        public static String absolutePath(final Package p, final String relativePath)
058        {
059                return absolutePath(p.getName(), relativePath);
060        }
061
062        /**
063         * Takes a package and a path to a resource and returns an absolute path to the resource. For
064         * example, if the given package was java.lang and the relative path was "../util/List", then
065         * "java/util/List" would be returned. An already absolute path stays absolute.
066         * <p>
067         * Note: The returned absolute path does not start with a slash ("/").
068         * 
069         * @param packageName
070         *            The package to start at
071         * @param path
072         *            The path to the resource
073         * @return The absolute path
074         */
075        public static String absolutePath(final String packageName, final String path)
076        {
077                // Is path already absolute?
078                if (path.startsWith("/"))
079                {
080                        return path.substring(1);
081                }
082                else
083                {
084                        // Break package into list of package names
085                        final StringList absolutePath = StringList.tokenize(packageName, ".");
086
087                        // Break path into folders
088                        final StringList folders = StringList.tokenize(path, "/\\");
089
090                        // Iterate through folders
091                        for (int i = 0, size = folders.size(); i < size; i++)
092                        {
093                                // Get next folder
094                                final String folder = folders.get(i);
095
096                                // Up one?
097                                if ("..".equals(folder))
098                                {
099                                        // Pop off stack
100                                        if (absolutePath.size() > 0)
101                                        {
102                                                absolutePath.removeLast();
103                                        }
104                                        else
105                                        {
106                                                throw new IllegalArgumentException("Invalid path " + path);
107                                        }
108                                }
109                                else if (".".equals(folder) == false)
110                                {
111                                        // Add to stack
112                                        absolutePath.add(folder);
113                                }
114                        }
115
116                        // Return absolute path
117                        return absolutePath.join("/");
118                }
119        }
120
121        /**
122         * Determines the package name for the given class.
123         * 
124         * @param forClass
125         *            the class
126         * @return the package name
127         */
128        public static String extractPackageName(final Class<?> forClass)
129        {
130                return parent(forClass.getName());
131        }
132
133        /**
134         * Gets the parent package name.
135         * 
136         * @param packageName
137         *            The Package name
138         * @return The parent Package
139         */
140        public static String parent(final String packageName)
141        {
142                int pos = packageName.lastIndexOf(".");
143                String parent;
144                if (pos < 0)
145                {
146                        pos = packageName.lastIndexOf("/");
147                        if (pos < 0)
148                        {
149                                pos = 0;
150                        }
151                }
152                parent = packageName.substring(0, pos);
153                return parent;
154        }
155
156
157        /**
158         * Resolve scope for the given class by extracting it's package name and converting all dots to
159         * slashes.
160         * 
161         * @param forClass
162         *            the class
163         * @return the scope string
164         */
165        public static String resolveScope(final Class<?> forClass)
166        {
167                String packName = extractPackageName(forClass);
168                return packName.replace('.', '/');
169        }
170
171        /**
172         * Instantiation not allowed.
173         */
174        private Packages()
175        {
176        }
177}