001    package org.apache.archiva.webdav.util;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *  http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.apache.jackrabbit.webdav.DavResource;
024    import org.apache.jackrabbit.webdav.io.OutputContext;
025    
026    import java.io.File;
027    import java.io.PrintWriter;
028    import java.text.DateFormat;
029    import java.util.ArrayList;
030    import java.util.Arrays;
031    import java.util.Collections;
032    import java.util.Date;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Locale;
036    import java.util.Map;
037    
038    /**
039     */
040    public class IndexWriter
041    {
042        private final String logicalResource;
043    
044        private final List<File> localResources;
045    
046        private final boolean isVirtual;
047    
048        public IndexWriter( DavResource resource, File localResource, String logicalResource )
049        {
050            this.localResources = new ArrayList<File>();
051            this.localResources.add( localResource );
052            this.logicalResource = logicalResource;
053            this.isVirtual = false;
054        }
055    
056        public IndexWriter( DavResource resource, List<File> localResources, String logicalResource )
057        {
058            this.logicalResource = logicalResource;
059            this.localResources = localResources;
060            this.isVirtual = true;
061        }
062    
063        public void write( OutputContext outputContext )
064        {
065            outputContext.setModificationTime( new Date().getTime() );
066            outputContext.setContentType( "text/html" );
067            outputContext.setETag( "" ); // skygo ETag MRM-1127 seems to be fixed
068            if ( outputContext.hasStream() )
069            {
070                PrintWriter writer = new PrintWriter( outputContext.getOutputStream() );
071                writeDocumentStart( writer );
072                writeHyperlinks( writer );
073                writeDocumentEnd( writer );
074                writer.flush();
075                writer.close();
076            }
077        }
078    
079        private void writeDocumentStart( PrintWriter writer )
080        {
081            writer.println("<!DOCTYPE html>");
082            writer.println( "<html>" );
083            writer.println( "<head>" );
084            writer.println( "<title>Collection: /" + logicalResource + "</title>" );
085            writer.println( "<style type=\"text/css\">" );
086            writer.println( "ul{list-style:none;}" ); 
087            
088            StringBuilder relative = new StringBuilder("../../");
089            if ( logicalResource.length() > 0 ) 
090            {
091                String tmpRelative = StringUtils.replace( logicalResource, "\\", "/" );
092                for (int i=0;i<tmpRelative.split("/").length;i++) 
093                {
094                    relative.append("../");
095                }
096            }
097            writer.println( ".file{background:url(" + relative.toString() + "images/package-x-generic.png) no-repeat scroll 0 0 transparent;}" );
098            writer.println( ".folder{background:url(" + relative.toString() + "images/folder.png) no-repeat scroll 0 0 transparent;}" );
099            writer.println( "a{color:#0088CC;text-decoration: none;padding-left:20px;}" );
100            writer.println( ".collection tr:nth-child(odd){background-color:#fafafa;}" );
101            writer.println( "tr td:nth-child(2){width:150px;color:#cc8800;text-align:right;}" );
102            writer.println( "tr td:nth-child(3){width:150px;color:#0000cc;text-align:center;}" );
103            writer.println( "th td:nth-child(2){width:150px;}" );
104            writer.println( "th td:nth-child(3){width:150px;}" );
105            writer.println( "</style>" );
106            writer.println( "<link rel=\"shortcut icon\" href=\"../../favicon.ico\"/>" );
107            writer.println( "</head>" );
108            writer.println( "<body>" );
109            writer.println( "<h3>Collection: /" + logicalResource + "</h3>" );
110    
111            //Check if not root
112            if ( logicalResource.length() > 0 )
113            {
114                File file = new File( logicalResource );
115                String parentName = file.getParent() == null ? "/" : file.getParent();
116    
117                //convert to unix path in case archiva is hosted on windows
118                parentName = StringUtils.replace( parentName, "\\", "/" );
119    
120                writer.println( "<ul>" );
121                writer.println( "<li><a class=\"folder\" href=\"../\">" + parentName + "</a> <i><small>(Parent)</small></i></li>" );
122                writer.println( "</ul>" );
123            }
124    
125            writer.println( "<table class=\"collection\">" );
126            writer.println( "<tr><th>Name</th><th>Size (Bytes)</th><th>Last Modified</th></tr>" );
127        }
128    
129        private void writeDocumentEnd( PrintWriter writer )
130        {
131            writer.println( "</table>" );
132            writer.println( "</body>" );
133            writer.println( "</html>" );
134        }
135    
136        private void writeHyperlinks( PrintWriter writer )
137        {
138            if ( !isVirtual )
139            {
140                for ( File localResource : localResources )
141                {
142                    List<File> files = new ArrayList<File>( Arrays.asList( localResource.listFiles() ) );
143                    Collections.sort( files );
144    
145                    for ( File file : files )
146                    {
147                        writeHyperlink( writer, file.getName(), file.lastModified(), file.length(), file.isDirectory() );
148                    }
149                }
150            }
151            else
152            {
153                // virtual repository - filter unique directories
154                Map<String, List<String>> uniqueChildFiles = new HashMap<String, List<String>>();
155                List<String> sortedList = new ArrayList<String>();
156                for ( File resource : localResources )
157                {
158                    List<File> files = new ArrayList<File>( Arrays.asList( resource.listFiles() ) );
159                    for ( File file : files )
160                    {
161                        List<String> mergedChildFiles = new ArrayList<String>();
162                        if ( uniqueChildFiles.get( file.getName() ) == null )
163                        {
164                            mergedChildFiles.add( file.getAbsolutePath() );
165                        }
166                        else
167                        {
168                            mergedChildFiles = uniqueChildFiles.get( file.getName() );
169                            if ( !mergedChildFiles.contains( file.getAbsolutePath() ) )
170                            {
171                                mergedChildFiles.add( file.getAbsolutePath() );
172                            }
173                        }
174                        uniqueChildFiles.put( file.getName(), mergedChildFiles );
175                        sortedList.add( file.getName() );
176                    }
177                }
178    
179                Collections.sort( sortedList );
180                List<String> written = new ArrayList<String>();
181                for ( String fileName : sortedList )
182                {
183                    List<String> childFilesFromMap = uniqueChildFiles.get( fileName );
184                    for ( String childFilePath : childFilesFromMap )
185                    {
186                        File childFile = new File( childFilePath );
187                        if ( !written.contains( childFile.getName() ) )
188                        {
189                            written.add( childFile.getName() );
190                            writeHyperlink( writer, fileName, childFile.lastModified(), childFile.length(), childFile.isDirectory() );
191                        }
192                    }
193                }
194            }
195        }
196    
197        private static String fileDateFormat( long date ) 
198        {
199            DateFormat dateFormatter = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault() );
200            Date aDate = new Date( date );
201            return dateFormatter.format( aDate );
202        }
203        
204        private void writeHyperlink( PrintWriter writer, String resourceName, long lastModified, long fileSize, boolean directory )
205        {
206            if ( directory )
207            {
208                writer.println( "<tr><td><a class=\"folder\" href=\"" + resourceName + "/\">" + resourceName + "</a></td><td>&nbsp;</td><td>&nbsp;</td></tr>" );
209            }
210            else
211            {
212                writer.println( "<tr><td><a class=\"file\" href=\"" + resourceName + "\">" + resourceName + "</a></td><td class=\"size\">" + fileSize + "&nbsp;&nbsp;</td><td class=\"date\">" + fileDateFormat( lastModified ) + "</td></tr>" );
213            }
214        }
215    }