/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.plugins.platform.content.yum;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.concurrent.locks.ReentrantLock;
/**
* Represends the yum <i>repomd.xml</i> file. This file contains information about the other metadata files.
*
* @author jortel
*/
public class Repomd extends Content {
/**
* file mutex.
*/
private static ReentrantLock lock = new ReentrantLock();
/**
* Construct with an active yum request.
*
* @param request An active yum request.
*/
public Repomd(Request request) {
super(request);
}
/*
* (non-Javadoc) @see org.jboss.on.plugins.platform.content.yum.Content#openStream()
*/
@Override
public InputStream openStream() throws Exception {
return new FileInputStream(file());
}
/*
* (non-Javadoc) @see org.jboss.on.plugins.platform.content.yum.Content#writeHeader(java.io.OutputStream)
*/
@Override
public void writeHeader(OutputStream ostr) throws Exception {
PrintWriter writer = new PrintWriter(ostr);
writer.printf("HTTP/1.1 200\n");
writer.println("Server: Ackbar (Red Hat)");
writer.println("Content-Type: text/xml; charset=utf-8");
writer.printf("Content-Length: %d\n\n", length());
writer.flush();
}
/*
* (non-Javadoc) @see org.jboss.on.plugins.platform.content.yum.Content#writeContent(java.io.OutputStream)
*/
@Override
public void writeContent(OutputStream ostr) throws Exception {
InputStream istr = openStream();
transfer(istr, ostr);
istr.close();
}
/*
* (non-Javadoc) @see org.jboss.on.plugins.platform.content.yum.Content#length()
*/
@Override
public long length() throws Exception {
return file().length();
}
/*
* (non-Javadoc) @see org.jboss.on.plugins.platform.content.yum.Content#delete()
*/
@Override
public void delete() {
lock.lock();
try {
new File(filepath()).delete();
} finally {
lock.unlock();
}
}
/**
* Get the <i>local</i> file object. The file is created if it doesn't already exist.
*
* @return The <i>local</i> file object.
*
* @throws Exception On all errors.
*/
File file() throws Exception {
lock.lock();
try {
File file = new File(filepath());
if (!file.exists()) {
create(file);
}
return file;
} finally {
lock.unlock();
}
}
/**
* Build and return the <i>local</i> file path.
*
* @return The <i>local</i> file path.
*/
String filepath() {
return new File(context().getTemporaryDirectory(), "repomd.xml").getAbsolutePath();
}
/**
* Create the <i>local</i> file representation of this metadata file. Since this file needs to contain the checksum
* of the primary.xml file, this method ensures that the Primary object is created and up to date.
*
* @param file The repomd.xml file to be created.
*
* @throws Exception On all errors.
*/
private void create(File file) throws Exception {
PrintWriter writer = new PrintWriter(file);
writer.append("<repomd xmlns=\"http://linux.duke.edu/metadata/repo\">");
writeEntry(writer, "other", 0, "0");
writeEntry(writer, "filelists", 0, "0");
Primary primary = new Primary(request);
long ts = primary.file().lastModified();
String checksum = sha(primary.openStream());
writeEntry(writer, "primary", ts, checksum);
writer.append("</repomd>");
writer.flush();
writer.close();
}
/**
* Writes and XML entry for the specified metadata file.
*
* @param writer An open writer.
* @param type The type of entry.
* @param ts The metadata file timestamp.
* @param sum The metadata file checksum.
*/
private void writeEntry(PrintWriter writer, String type, long ts, String sum) {
writer.printf("\t<data type=\"%s\">", type);
writer.printf("\t<location href=\"repodata/%s.xml\"/>", type);
writer.printf("\t<checksum type=\"sha\">%s</checksum>", sum);
writer.printf("\t<timestamp>%d</timestamp>", ts);
writer.append("\t</data>");
}
/**
* Get the SHA checksum for the metadata file using the provided input stream.
*
* @param istr An input stream opened on the metadata file.
*
* @return The SHA checksum in hex digits for the file.
*
* @throws Exception On all errors.
*/
String sha(InputStream istr) throws Exception {
byte[] bfr = new byte[10240];
MessageDigest md = MessageDigest.getInstance("SHA");
DigestInputStream mdistr = new DigestInputStream(istr, md);
while (mdistr.read(bfr) != -1) {
;
}
mdistr.close();
byte[] b = md.digest();
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
}