001    package org.deegree.portal.standard.security.control;
002    
003    import java.io.File;
004    import java.text.ParseException;
005    import java.util.Collection;
006    import java.util.Iterator;
007    import java.util.Vector;
008    
009    /**
010     * TODO add documentation here
011     * 
012     * @author <a href="mailto:elmasry@lat-lon.de">Moataz Elmasry</a>
013     * @author last edited by: $Author: elmasri$
014     * 
015     * @version $Revision: $, $Date: 08-Mar-2007 16:46:12$
016     */
017    public class RelativePath {
018    
019        /**
020         * get the first match from the many delimiters give as input
021         * 
022         * @param source
023         * @param delimiters
024         * @return String
025         */
026        public static String getFirstMatch( String source, String[] delimiters ) {
027    
028            Vector<Delimiter> indices = new Vector<Delimiter>();
029    
030            for ( int i = 0; i < delimiters.length; i++ ) {
031                // we added the indices of all matches to the vector
032                indices.add( new Delimiter( i, source.indexOf( delimiters[i] ), delimiters[i] ) );
033            }
034    
035            Delimiter delimiter = getFirstIndex( indices );
036            if ( delimiter.getValue() == null ) {
037                return null;
038            }
039    
040            return source.substring( 0, delimiter.getFoundAt() + 1 );
041        }
042    
043        /**
044         * Gets the first index of a match from the many delimiters given as input Takes many delimiters
045         * returns the delimiter that occured first
046         * 
047         * @param collection
048         * @return instance of Delimiter class
049         */
050        private static Delimiter getFirstIndex( Collection<Delimiter> collection ) {
051    
052            Delimiter delimiter = new Delimiter( -1, 999, null );
053            Iterator it = collection.iterator();
054            // comparing the matches to see which match occured first
055            while ( it.hasNext() ) {
056                Delimiter temp = (Delimiter) it.next();
057                int indexOf = temp.foundAt;
058                if ( indexOf < delimiter.getFoundAt() && indexOf > -1 ) {
059                    delimiter = temp;
060                }
061            }
062    
063            if ( delimiter == null ) {
064                return null;
065            }
066            return delimiter;
067    
068        }
069    
070        /**
071         * Split a string based on the given delimiters and return an array of strings(tokens)
072         * 
073         * @param source
074         * @param delimiters
075         * @return tokens from a given string
076         */
077        public static String[] splitString( String source, String[] delimiters ) {
078    
079            if ( source == null || delimiters == null )
080                return null;
081    
082            Vector<String> returnedStrings = new Vector<String>();
083            String tempSource = source;
084    
085            while ( tempSource.length() != 0 ) {
086    
087                int delimiterLength = 0;
088                String match = getFirstMatch( tempSource, delimiters );
089                // if this is the last token in the String
090                if ( match == null ) {
091                    returnedStrings.add( tempSource );
092                    break;
093                } else {
094    
095                    // removing any delimiters that could exist
096                    for ( int i = 0; i < delimiters.length; i++ ) {
097                        if ( match.contains( delimiters[i] ) ) {
098                            match = match.replace( delimiters[i], "" );
099                            delimiterLength = delimiters[i].length();
100                            break;
101                        }
102    
103                    }
104                    // Ignore the ./ and don't add it to the array
105                    if ( match.compareTo( "./" ) != 0 ) {
106                        returnedStrings.add( match );
107                    }
108                    tempSource = tempSource.substring( match.length() + delimiterLength, tempSource.length() );
109                }
110    
111            }
112    
113            String[] strings = new String[returnedStrings.size()];
114            for ( int i = 0; i < returnedStrings.size(); i++ ) {
115                strings[i] = returnedStrings.elementAt( i );
116            }
117            return strings;
118        }
119    
120        /**
121         * Maps from a source sTring to a target String, based on the delimiters given the delimiters
122         * are basically "\\" or "/", but it also could be anything else Two absolute pathes should be
123         * given here Don't give relative or non existing pathes
124         * 
125         * @param source
126         * @param target
127         * @param delimiters
128         * @return the mapped path
129         * @throws ParseException
130         */
131        public static String mapRelativePath( String source, String target, String[] delimiters )
132                                throws ParseException {
133    
134            if ( !new File( source ).isAbsolute() ) {
135                throw new ParseException( "The source path is not absolute", 0 );
136            }
137            if ( !new File( target ).isAbsolute() ) {
138                throw new ParseException( "The target path is not absolute", 0 );
139            }
140    
141            String[] sourceTokens = splitString( source, delimiters );
142            String[] targetTokens = splitString( target, delimiters );
143            if ( sourceTokens == null || targetTokens == null )
144                return null;
145            if ( sourceTokens.length == 0 || targetTokens.length == 0 )
146                return null;
147    
148            int lessTokens = 0;
149            if ( sourceTokens.length < targetTokens.length ) {
150                lessTokens = sourceTokens.length;
151            } else {
152                lessTokens = targetTokens.length;
153            }
154    
155            int counter = 0;
156            for ( counter = 0; counter < lessTokens; counter++ ) {
157                if ( !sourceTokens[counter].equals( targetTokens[counter] ) )
158                    break;
159            }
160    
161            StringBuffer buffer = new StringBuffer();
162            for ( int i = counter; i < sourceTokens.length; i++ ) {
163                if ( i != sourceTokens.length - 1 ) {
164                    buffer.append( "../" );
165                } else {
166                    // We are checking if the last token in the source String is a file or a directory
167                    // if its a file we don'tn write it
168                    File sourceFile = new File( source );
169                    if ( sourceFile.isDirectory() ) {
170                        buffer.append( "../" );
171                    }
172                }
173    
174            }
175    
176            // This is used when the target is only one token different/larger than the source, so we
177            // just take
178            // the last token in the target
179            if ( ( counter == sourceTokens.length ) && ( sourceTokens.length == targetTokens.length + 1 )
180                 && ( sourceTokens[counter - 1].equals( targetTokens[counter - 1] ) ) ) {
181                return targetTokens[targetTokens.length - 1];
182            }
183            for ( int i = counter; i < targetTokens.length; i++ ) {
184                if ( buffer.length() == 0 ) {
185                    // This is the first token in the path
186                    buffer.append( "./" );
187                }
188                buffer.append( targetTokens[i] );
189                if ( i != targetTokens.length - 1 ) {
190                    buffer.append( "/" );
191                }
192    
193            }
194    
195            return buffer.toString();
196        }
197    
198        static class Delimiter {
199            int index;
200    
201            String value;
202    
203            int foundAt;
204    
205            /**
206             * @param index
207             * @param foundAt
208             * @param value
209             */
210            public Delimiter( int index, int foundAt, String value ) {
211                this.index = index;
212                this.value = value;
213                this.foundAt = foundAt;
214            }
215    
216            /**
217             * @return int
218             */
219            public int getIndex() {
220                return index;
221            }
222    
223            /**
224             * @param index
225             */
226            public void setIndex( int index ) {
227                this.index = index;
228            }
229    
230            /**
231             * @return String
232             */
233            public String getValue() {
234                return value;
235            }
236    
237            /**
238             * @param value
239             */
240            public void setValue( String value ) {
241                this.value = value;
242            }
243    
244            /**
245             * @return int
246             */
247            public int getFoundAt() {
248                return foundAt;
249            }
250    
251            /**
252             * @param foundAt
253             */
254            public void setFoundAt( int foundAt ) {
255                this.foundAt = foundAt;
256            }
257        }
258    
259    }