001package 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 022import org.apache.commons.lang.StringUtils; 023import org.apache.jackrabbit.webdav.DavResource; 024import org.apache.jackrabbit.webdav.io.OutputContext; 025 026import java.io.File; 027import java.io.PrintWriter; 028import java.text.DateFormat; 029import java.util.ArrayList; 030import java.util.Arrays; 031import java.util.Collections; 032import java.util.Date; 033import java.util.HashMap; 034import java.util.List; 035import java.util.Locale; 036import java.util.Map; 037 038/** 039 */ 040public 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<>(); 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 != null && 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 != null && 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<>( 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<>(); 155 List<String> sortedList = new ArrayList<>(); 156 for ( File resource : localResources ) 157 { 158 List<File> files = new ArrayList<>( Arrays.asList( resource.listFiles() ) ); 159 for ( File file : files ) 160 { 161 List<String> mergedChildFiles = new ArrayList<>(); 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<>(); 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> </td><td> </td></tr>" ); 209 } 210 else 211 { 212 writer.println( "<tr><td><a class=\"file\" href=\"" + resourceName + "\">" + resourceName + "</a></td><td class=\"size\">" + fileSize + " </td><td class=\"date\">" + fileDateFormat( lastModified ) + "</td></tr>" ); 213 } 214 } 215}