--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+<?xml version="1.0"?>
+
+<project name="jSite" default="compile">
+
+ <!-- create this file if you want to re-distribute jSite -->
+ <property file="build.properties" />
+
+ <!-- default values if no build.properties is present -->
+ <property name="version" value="custom" />
+ <property name="javac.debug" value="false" />
+
+ <property name="src.dir" value="${basedir}/src" />
+ <property name="bin.dir" value="${basedir}/build" />
+ <property name="dist.dir" value="${basedir}/dist" />
+ <property name="images.dir" value="${basedir}/images" />
+
+ <!-- if the next lines fails, disable or delete it. you don't need it. unless you stole my development machine. -->
+ <available filepath="${basedir}/../todesbaum-lib" file="build.xml" property="maintainer-build" />
+ <available filepath="${basedir}/../todesbaum-lib" file="build.xml" property="todesbaum.src" value="${basedir}/../todesbaum-lib/src" />
+
+ <!-- default values for non-maintainer builds -->
+ <property name="todesbaum.src" value="${src.dir}" />
+
+ <target name="prepare">
+ <mkdir dir="${bin.dir}" />
+ </target>
+
+ <target name="compile-maintainer" depends="prepare" if="maintainer-build">
+ <javac destdir="${bin.dir}" debug="false" optimize="true">
+ <src path="${src.dir}" />
+ <sourcepath path="${todesbaum.src}" />
+ </javac>
+ </target>
+
+ <target name="compile-non-maintainer" depends="prepare" unless="maintainer-build">
+ <javac destdir="${bin.dir}" debug="false" optimize="true">
+ <src path="${src.dir}" />
+ <sourcepath path="${todesbaum.src}" />
+ </javac>
+ </target>
+
+ <target name="compile" depends="compile-maintainer, compile-non-maintainer" description="compile jSite">
+ <copy todir="${bin.dir}">
+ <fileset dir="${src.dir}">
+ <include name="**/*.properties" />
+ </fileset>
+ <fileset dir="${images.dir}">
+ <include name="**/*.png" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="clean" description="cleans the build environment">
+ <delete dir="${bin.dir}" />
+ </target>
+
+ <target name="dist-clean" depends="clean" description="cleans build and distribution environments">
+ <delete dir="${dist.dir}" />
+ </target>
+
+ <target name="prepare-dist">
+ <mkdir dir="${dist.dir}" />
+ </target>
+
+ <target name="prepare-src-dist" depends="prepare-dist">
+ <mkdir dir="${dist.dir}/${ant.project.name}-${version}" />
+ <mkdir dir="${dist.dir}/${ant.project.name}-${version}/src" />
+ <mkdir dir="${dist.dir}/${ant.project.name}-${version}/images" />
+ </target>
+
+ <target name="jar" depends="compile, prepare-dist" description="creates jSite jar file">
+ <jar destfile="${dist.dir}/${ant.project.name}.jar">
+ <fileset dir="${bin.dir}" />
+ <manifest>
+ <attribute name="Main-Class" value="de.todesbaum.jsite.main.Main"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="dist-bin-zip" depends="jar" description="create binary distribution zip">
+ <zip destfile="${dist.dir}/${ant.project.name}-${version}-bin.zip">
+ <fileset dir="${dist.dir}">
+ <include name="${ant.project.name}.jar" />
+ </fileset>
+ <fileset dir="${basedir}">
+ <include name="COPYING" />
+ </fileset>
+ </zip>
+ </target>
+
+ <target name="dist-bin-tbz2" depends="jar" description="create binary distribution tar.bz2">
+ <tar destfile="${dist.dir}/${ant.project.name}-${version}-bin.tar.bz2" compression="bzip2">
+ <tarfileset dir="${dist.dir}">
+ <include name="${ant.project.name}.jar" />
+ </tarfileset>
+ <tarfileset dir="${basedir}">
+ <include name="COPYING" />
+ </tarfileset>
+ </tar>
+ </target>
+
+ <target name="dist-bin" depends="dist-bin-zip, dist-bin-tbz2"/>
+
+ <target name="collect-maintainer-src" depends="prepare-src-dist" if="maintainer-build">
+ <copy todir="${dist.dir}/${ant.project.name}-${version}/src">
+ <fileset dir="${todesbaum.src}">
+ <includesfile name="build.collect-src.files" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="collect-src" depends="prepare-src-dist, collect-maintainer-src">
+ <copy todir="${dist.dir}/${ant.project.name}-${version}/src">
+ <fileset dir="${src.dir}">
+ <include name="**/*.java" />
+ <include name="**/*.properties" />
+ </fileset>
+ </copy>
+ <copy todir="${dist.dir}/${ant.project.name}-${version}/images">
+ <fileset dir="${images.dir}">
+ <include name="**/*.png" />
+ </fileset>
+ </copy>
+ <copy todir="${dist.dir}/${ant.project.name}-${version}">
+ <fileset dir="${basedir}">
+ <include name="COPYING" />
+ <include name="build.xml" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="dist-src" depends="dist-src-zip, dist-src-tbz2" />
+
+ <target name="dist-src-zip" depends="collect-src" description="create source distribution zip">
+ <zip destfile="${dist.dir}/${ant.project.name}-${version}-src.zip">
+ <fileset dir="${dist.dir}">
+ <include name="${ant.project.name}-${version}/**/*" />
+ </fileset>
+ </zip>
+ </target>
+
+ <target name="dist-src-tbz2" depends="collect-src" description="create source distribution tar.bz2">
+ <tar destfile="${dist.dir}/${ant.project.name}-${version}-src.tar.bz2" compression="bzip2">
+ <tarfileset dir="${dist.dir}">
+ <include name="${ant.project.name}-${version}/**/*" />
+ </tarfileset>
+ </tar>
+ </target>
+
+ <target name="dist" depends="dist-bin, dist-src" description="creates all distribution files"/>
+
+ <target name="build-collect-src" depends="clean, compile" if="maintainer-build">
+ <exec executable="/bin/sh" output="build.collect-src.files">
+ <arg value="-c"/>
+ <arg value="find build -type f | grep -v '\$' | sed 's,^build/,,' | grep '^de/todesbaum/util/' | sed 's,class$,java,'" />
+ </exec>
+ </target>
+
+</project>
+
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+/**
+ * Project extension for edition-based projects. In Freenet 0.7 this is
+ * currently the only project type.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: EditionProject.java 417 2006-03-29 12:36:54Z bombe $
+ */
+public class EditionProject extends Project {
+
+ /** The edition to insert to. */
+ private int edition;
+
+ /**
+ * Creates a new edition-based project.
+ */
+ public EditionProject() {
+ }
+
+ /**
+ * Clones the specified project as an edition-based project.
+ *
+ * @param project
+ * The project to clone
+ */
+ public EditionProject(Project project) {
+ super(project);
+ if (project instanceof EditionProject) {
+ edition = ((EditionProject) project).edition;
+ }
+ }
+
+ /**
+ * Returns the edition of the project.
+ *
+ * @return The edition of the project
+ */
+ public int getEdition() {
+ return edition;
+ }
+
+ /**
+ * Sets the edition of the project.
+ *
+ * @param edition
+ * The edition to set
+ */
+ public void setEdition(int edition) {
+ this.edition = edition;
+ }
+
+ /**
+ * Constructs the final request URI including the edition number.
+ *
+ * @return The final request URI
+ */
+ @Override
+ public String getFinalURI(int editionOffset) {
+ return requestURI + path + "-" + (edition + editionOffset) + "/";
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+public class FileOption {
+
+ private static final boolean DEFAULT_INSERT = true;
+ private static final String DEFAULT_CUSTOM_KEY = "CHK@";
+ private static final String DEFAULT_CONTAINER = "";
+ private static final int DEFAULT_EDITION_RANGE = 3;
+ private static final boolean DEFAULT_REPLACE_EDITION = false;
+
+ private boolean insert;
+ private String customKey;
+ private final String defaultMimeType;
+ private String mimeType;
+ private String container;
+ private int editionRange;
+ private boolean replaceEdition;
+
+ public FileOption(String defaultMimeType) {
+ insert = DEFAULT_INSERT;
+ customKey = DEFAULT_CUSTOM_KEY;
+ this.defaultMimeType = defaultMimeType;
+ this.mimeType = defaultMimeType;
+ this.container = DEFAULT_CONTAINER;
+ this.editionRange = DEFAULT_EDITION_RANGE;
+ this.replaceEdition = DEFAULT_REPLACE_EDITION;
+ }
+
+ /**
+ * @return Returns the customKey.
+ */
+ public String getCustomKey() {
+ return customKey;
+ }
+
+ /**
+ * @param customKey
+ * The customKey to set.
+ */
+ public void setCustomKey(String customKey) {
+ if (customKey == null) {
+ customKey = "";
+ }
+ this.customKey = customKey;
+ }
+
+ /**
+ * @return Returns the insert.
+ */
+ public boolean isInsert() {
+ return insert;
+ }
+
+ /**
+ * @param insert
+ * The insert to set.
+ */
+ public void setInsert(boolean insert) {
+ this.insert = insert;
+ }
+
+ public void setMimeType(String mimeType) {
+ if (mimeType == null) {
+ mimeType = defaultMimeType;
+ }
+ this.mimeType = mimeType;
+ }
+
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ /**
+ * @return Returns the container.
+ */
+ public String getContainer() {
+ return container;
+ }
+
+ /**
+ * @param container
+ * The container to set.
+ */
+ public void setContainer(String container) {
+ if (container == null) {
+ container = DEFAULT_CONTAINER;
+ }
+ this.container = container;
+ }
+
+ public void setReplaceEdition(boolean replaceEdition) {
+ this.replaceEdition = replaceEdition;
+ }
+
+ public boolean getReplaceEdition() {
+ return replaceEdition;
+ }
+
+ public void setEditionRange(int editionRange) {
+ this.editionRange = editionRange;
+ }
+
+ public int getEditionRange() {
+ return editionRange;
+ }
+
+ public boolean isCustom() {
+ if (insert != DEFAULT_INSERT)
+ return true;
+ if (!customKey.equals(DEFAULT_CUSTOM_KEY))
+ return true;
+ if (!defaultMimeType.equals(mimeType))
+ return true;
+ if (!DEFAULT_CONTAINER.equals(container))
+ return true;
+ if (replaceEdition != DEFAULT_REPLACE_EDITION)
+ return true;
+ if (editionRange != DEFAULT_EDITION_RANGE)
+ return true;
+ return false;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.IOException;
+
+import de.todesbaum.util.freenet.fcp2.Client;
+import de.todesbaum.util.freenet.fcp2.Connection;
+import de.todesbaum.util.freenet.fcp2.GenerateSSK;
+import de.todesbaum.util.freenet.fcp2.Message;
+import de.todesbaum.util.freenet.fcp2.Node;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Freenet7Interface.java 418 2006-03-29 17:49:16Z bombe $
+ */
+public class Freenet7Interface {
+
+ private static int counter = 0;
+
+ private Node node;
+ private Connection connection;
+
+ public void setNodeAddress(String hostname) {
+ node = new Node(hostname);
+ connection = new Connection(node, "connection-" + counter++);
+ }
+
+ public void setNodeAddress(String hostname, int port) {
+ node = new Node(hostname, port);
+ connection = new Connection(node, "connection-" + counter++);
+ }
+
+ public void setNode(de.todesbaum.jsite.application.Node node) {
+ if (node != null) {
+ this.node = new Node(node.getHostname(), node.getPort());
+ connection = new Connection(node, "connection-" + counter++);
+ } else {
+ this.node = null;
+ connection = null;
+ }
+ }
+
+ public void removeNode() {
+ node = null;
+ connection = null;
+ }
+
+ /**
+ * @return Returns the node.
+ */
+ public Node getNode() {
+ return node;
+ }
+
+ /**
+ * @return Returns the connection.
+ */
+ public Connection getConnection(String identifier) {
+ return new Connection(node, identifier);
+ }
+
+ public boolean isNodePresent() throws IOException {
+ if (!connection.isConnected()) {
+ return connection.connect();
+ }
+ return true;
+ }
+
+ public String[] generateKeyPair() throws IOException {
+ if (!isNodePresent()) {
+ return null;
+ }
+ GenerateSSK generateSSK = new GenerateSSK();
+ Client client = new Client(connection, generateSSK);
+ Message keypairMessage = client.readMessage();
+ return new String[] { keypairMessage.get("InsertURI"), keypairMessage.get("RequestURI") };
+ }
+
+ /**
+ * @return <code>true</code> if this interface already has a node set,
+ * <code>false</code> otherwise
+ */
+ public boolean hasNode() {
+ return (node != null) && (connection != null);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.util.EventListener;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: InsertListener.java 397 2006-03-25 16:11:34Z bombe $
+ */
+public interface InsertListener extends EventListener {
+
+ public static enum ErrorType {
+ KEY_COLLISION, ROUTE_NOT_FOUND, DATA_NOT_FOUND, FCP_ERROR, IO_ERROR
+ }
+
+ public void projectInsertStarted(Project project);
+
+ public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized);
+
+ public void projectInsertFinished(Project project, boolean success, Throwable cause);
+
+}
--- /dev/null
+/*
+ * jSite-0.7 -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Node.java 419 2006-03-29 17:49:46Z bombe $
+ */
+public class Node extends de.todesbaum.util.freenet.fcp2.Node {
+
+ protected String name;
+
+ /**
+ * @param hostname
+ */
+ public Node(String hostname) {
+ this(hostname, DEFAULT_PORT);
+ }
+
+ /**
+ * @param hostname
+ * @param port
+ */
+ public Node(String hostname, int port) {
+ this(hostname, port, "");
+ }
+
+ public Node(String hostname, int port, String name) {
+ super(hostname, port);
+ this.name = name;
+ }
+
+ public Node(Node node) {
+ this(node.getHostname(), node.getPort());
+ }
+
+ public Node(Node node, String name) {
+ this(node.getHostname(), node.getPort(), name);
+ }
+
+ /**
+ * @param name
+ * The name to set.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return Returns the name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof Node)) {
+ return false;
+ }
+ Node node = (Node) o;
+ return name.equals(node.name) && hostname.equals(node.hostname) && (port == node.port);
+ }
+
+ public int hashCode() {
+ return name.hashCode() ^ hostname.hashCode() ^ port;
+ }
+
+ public String toString() {
+ return name + " (" + hostname + ":" + port + ")";
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import de.todesbaum.util.mime.DefaultMIMETypes;
+
+/**
+ * @author David Roden <dr@todesbaum.dyndns.org>
+ * @version $Id: Project.java 357 2006-03-24 15:46:03Z bombe $
+ */
+public abstract class Project implements Comparable {
+
+ protected String name;
+ protected String description;
+
+ protected String insertURI;
+ protected String requestURI;
+
+ protected String indexFile;
+ protected String localPath;
+ protected String path;
+ protected long lastInsertionTime;
+
+ protected Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
+
+ public Project() {
+ }
+
+ /**
+ * Clone-constructor.
+ *
+ * @param project
+ */
+ public Project(Project project) {
+ name = project.name;
+ description = project.description;
+ insertURI = project.insertURI;
+ requestURI = project.requestURI;
+ path = project.path;
+ localPath = project.localPath;
+ indexFile = project.indexFile;
+ lastInsertionTime = project.lastInsertionTime;
+ fileOptions = new HashMap<String, FileOption>(project.fileOptions);
+ }
+
+ /**
+ * @return Returns the title.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param title
+ * The title to set.
+ */
+ public void setName(String title) {
+ this.name = title;
+ }
+
+ /**
+ * @return Returns the description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @param description
+ * The description to set.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * @return Returns the localPath.
+ */
+ public String getLocalPath() {
+ return localPath;
+ }
+
+ /**
+ * @param localPath
+ * The localPath to set.
+ */
+ public void setLocalPath(String localPath) {
+ this.localPath = localPath;
+ }
+
+ /**
+ * @return Returns the indexFile.
+ */
+ public String getIndexFile() {
+ return indexFile;
+ }
+
+ /**
+ * @param indexFile
+ * The indexFile to set.
+ */
+ public void setIndexFile(String indexFile) {
+ this.indexFile = indexFile;
+ }
+
+ /**
+ * @return Returns the lastInserted.
+ */
+ public long getLastInsertionTime() {
+ return lastInsertionTime;
+ }
+
+ /**
+ * @param lastInserted
+ * The lastInserted to set.
+ */
+ public void setLastInsertionTime(long lastInserted) {
+ this.lastInsertionTime = lastInserted;
+ }
+
+ /**
+ * @return Returns the name.
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @param name
+ * The name to set.
+ */
+ public void setPath(String name) {
+ this.path = name;
+ }
+
+ /**
+ * @return Returns the insertURI.
+ */
+ public String getInsertURI() {
+ return insertURI;
+ }
+
+ /**
+ * @param insertURI
+ * The insertURI to set.
+ */
+ public void setInsertURI(String insertURI) {
+ this.insertURI = insertURI;
+ }
+
+ /**
+ * @return Returns the requestURI.
+ */
+ public String getRequestURI() {
+ return requestURI;
+ }
+
+ /**
+ * @param requestURI
+ * The requestURI to set.
+ */
+ public void setRequestURI(String requestURI) {
+ this.requestURI = requestURI;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ public String shortenFilename(File file) {
+ String filename = file.getPath();
+ if (filename.startsWith(localPath)) {
+ filename = filename.substring(localPath.length());
+ if (filename.startsWith(File.separator)) {
+ filename = filename.substring(1);
+ }
+ }
+ return filename;
+ }
+
+ public FileOption getFileOption(String filename) {
+ FileOption fileOption = fileOptions.get(filename);
+ if (fileOption == null) {
+ fileOption = new FileOption(DefaultMIMETypes.guessMIMEType(filename));
+ fileOptions.put(filename, fileOption);
+ }
+ return fileOption;
+ }
+
+ public void setFileOption(String filename, FileOption fileOption) {
+ fileOptions.put(filename, fileOption);
+ }
+
+ /**
+ * @return Returns the fileOptions.
+ */
+ public Map<String, FileOption> getFileOptions() {
+ return Collections.unmodifiableMap(fileOptions);
+ }
+
+ /**
+ * @param fileOptions
+ * The fileOptions to set.
+ */
+ public void setFileOptions(Map<String, FileOption> fileOptions) {
+ this.fileOptions.clear();
+ this.fileOptions.putAll(fileOptions);
+ }
+
+ public String getFinalURI(int editionOffset) {
+ return requestURI + path + "/";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(Object o) {
+ return name.compareToIgnoreCase(((Project) o).name);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import de.todesbaum.jsite.gui.FileScanner;
+import de.todesbaum.jsite.gui.FileScannerListener;
+import de.todesbaum.util.freenet.fcp2.Client;
+import de.todesbaum.util.freenet.fcp2.ClientPutComplexDir;
+import de.todesbaum.util.freenet.fcp2.Connection;
+import de.todesbaum.util.freenet.fcp2.DirectFileEntry;
+import de.todesbaum.util.freenet.fcp2.FileEntry;
+import de.todesbaum.util.freenet.fcp2.Message;
+import de.todesbaum.util.freenet.fcp2.RedirectFileEntry;
+import de.todesbaum.util.freenet.fcp2.Verbosity;
+import de.todesbaum.util.io.ReplacingOutputStream;
+import de.todesbaum.util.io.StreamCopier;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ProjectInserter.java 440 2006-03-30 09:31:25Z bombe $
+ */
+public class ProjectInserter implements FileScannerListener, Runnable {
+
+ private static int counter = 0;
+ private boolean debug = false;
+ private List<InsertListener> insertListeners = new ArrayList<InsertListener>();
+ protected Freenet7Interface freenetInterface;
+ protected Project project;
+ private FileScanner fileScanner;
+ protected final Object lockObject = new Object();
+ private int maxRetries = 99999;
+
+ public void addInsertListener(InsertListener insertListener) {
+ insertListeners.add(insertListener);
+ }
+
+ public void removeInsertListener(InsertListener insertListener) {
+ insertListeners.remove(insertListener);
+ }
+
+ protected void fireProjectInsertStarted() {
+ for (InsertListener insertListener: insertListeners) {
+ insertListener.projectInsertStarted(project);
+ }
+ }
+
+ protected void fireProjectInsertProgress(int succeeded, int failed, int fatal, int total, boolean finalized) {
+ for (InsertListener insertListener: insertListeners) {
+ insertListener.projectInsertProgress(project, succeeded, failed, fatal, total, finalized);
+ }
+ }
+
+ protected void fireProjectInsertFinished(boolean success, Throwable cause) {
+ for (InsertListener insertListener: insertListeners) {
+ insertListener.projectInsertFinished(project, success, cause);
+ }
+ }
+
+ /**
+ * @param debug
+ * The debug to set.
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * @param project
+ * The project to set.
+ */
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * @param freenetInterface
+ * The freenetInterface to set.
+ */
+ public void setFreenetInterface(Freenet7Interface freenetInterface) {
+ this.freenetInterface = freenetInterface;
+ }
+
+ /**
+ * @param maxRetries
+ * The maxRetries to set.
+ */
+ public void setMaxRetries(int maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ public void start() {
+ fileScanner = new FileScanner(project);
+ fileScanner.addFileScannerListener(this);
+ new Thread(fileScanner).start();
+ }
+
+ private InputStream createFileInputStream(String filename, FileOption fileOption, int edition, long[] length) throws IOException {
+ File file = new File(project.getLocalPath(), filename);
+ length[0] = file.length();
+ if (!fileOption.getReplaceEdition()) {
+ return new FileInputStream(file);
+ }
+ ByteArrayOutputStream filteredByteOutputStream = new ByteArrayOutputStream(Math.min(Integer.MAX_VALUE, (int) length[0]));
+ ReplacingOutputStream outputStream = new ReplacingOutputStream(filteredByteOutputStream);
+ FileInputStream fileInput = new FileInputStream(file);
+ outputStream.addReplacement("$[CONTAINER]", "/");
+ outputStream.addReplacement("$[EDITION]", String.valueOf(edition));
+ outputStream.addReplacement("$[URI]", project.getFinalURI(0));
+ for (int index = 1; index <= fileOption.getEditionRange(); index++) {
+ outputStream.addReplacement("$[URI+" + index + "]", project.getFinalURI(index));
+ outputStream.addReplacement("$[URI+" + index + "]", project.getFinalURI(index));
+ }
+ StreamCopier.copy(fileInput, outputStream, length[0]);
+ outputStream.close();
+ filteredByteOutputStream.close();
+ byte[] filteredBytes = filteredByteOutputStream.toByteArray();
+ length[0] = filteredBytes.length;
+ return new ByteArrayInputStream(filteredBytes);
+ }
+
+ private InputStream createContainerInputStream(Map<String, List<String>> containerFiles, String containerName, int edition, long[] containerLength) throws IOException {
+ File tempFile = File.createTempFile("jsite", ".zip");
+ tempFile.deleteOnExit();
+ FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
+ ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
+ for (String filename: containerFiles.get(containerName)) {
+ File dataFile = new File(project.getLocalPath(), filename);
+ if (dataFile.exists()) {
+ ZipEntry zipEntry = new ZipEntry(filename);
+ long[] fileLength = new long[1];
+ InputStream wrappedInputStream = createFileInputStream(filename, project.getFileOption(filename), edition, fileLength);
+ zipOutputStream.putNextEntry(zipEntry);
+ StreamCopier.copy(wrappedInputStream, zipOutputStream, fileLength[0]);
+ zipOutputStream.closeEntry();
+ wrappedInputStream.close();
+ }
+ }
+ zipOutputStream.closeEntry();
+
+ /* FIXME - create metadata */
+ // ZipEntry metadataEntry = new ZipEntry("metadata");
+ // zipOutputStream.putNextEntry(metadataEntry);
+ // Metadata zipMetadata = new Metadata();
+ // for (String filename: containerFiles.get(containerName)) {
+ // if (new File(project.getLocalPath(), filename).exists()) {
+ // DocumentMetadata zipEntryMetadata = new DocumentMetadata();
+ // zipEntryMetadata.setName(filename);
+ // zipEntryMetadata.setFormat(project.getFileOption(filename).getMimeType());
+ // zipMetadata.addDocument(zipEntryMetadata);
+ // }
+ // }
+ // zipOutputStream.write(zipMetadata.toByteArray());
+ // zipOutputStream.closeEntry();
+ zipOutputStream.close();
+
+ containerLength[0] = tempFile.length();
+ return new FileInputStream(tempFile);
+ }
+
+ private FileEntry createFileEntry(String filename, int edition, Map<String, List<String>> containerFiles) {
+ FileEntry fileEntry = null;
+ FileOption fileOption = project.getFileOption(filename);
+ if (filename.startsWith("/container/:")) {
+ String containerName = filename.substring("/container/:".length());
+ try {
+ long[] containerLength = new long[1];
+ InputStream containerInputStream = createContainerInputStream(containerFiles, containerName, edition, containerLength);
+ fileEntry = new DirectFileEntry(containerName + ".zip", "application/zip", containerInputStream, containerLength[0]);
+ } catch (IOException ioe1) {
+ }
+ } else {
+ if (fileOption.isInsert()) {
+ try {
+ long[] fileLength = new long[1];
+ InputStream fileEntryInputStream = createFileInputStream(filename, fileOption, edition, fileLength);
+ fileEntry = new DirectFileEntry(filename, project.getFileOption(filename).getMimeType(), fileEntryInputStream, fileLength[0]);
+ } catch (IOException ioe1) {
+ }
+ } else {
+ fileEntry = new RedirectFileEntry(filename, fileOption.getMimeType(), fileOption.getCustomKey());
+ }
+ }
+ return fileEntry;
+ }
+
+ private void createContainers(List<String> files, List<String> containers, Map<String, List<String>> containerFiles) {
+ for (String filename: new ArrayList<String>(files)) {
+ FileOption fileOption = project.getFileOption(filename);
+ String containerName = fileOption.getContainer();
+ if (!containerName.equals("")) {
+ if (!containers.contains(containerName)) {
+ containers.add(containerName);
+ containerFiles.put(containerName, new ArrayList<String>());
+ /* hmm. looks like a hack to me. */
+ files.add("/container/:" + containerName);
+ }
+ containerFiles.get(containerName).add(filename);
+ files.remove(filename);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ fireProjectInsertStarted();
+ List<String> files = fileScanner.getFiles();
+
+ /* create connection to node */
+ Connection connection = freenetInterface.getConnection("project-insert-" + counter++);
+ try {
+ connection.connect();
+ } catch (IOException e1) {
+ fireProjectInsertFinished(false, e1);
+ return;
+ }
+ Client client = new Client(connection);
+
+ /* create containers */
+ final List<String> containers = new ArrayList<String>();
+ final Map<String, List<String>> containerFiles = new HashMap<String, List<String>>();
+ createContainers(files, containers, containerFiles);
+
+ /* collect files */
+ int edition = ((EditionProject) project).getEdition();
+ String dirURI = project.getInsertURI() + project.getPath() + "-" + edition;
+ ClientPutComplexDir putDir = new ClientPutComplexDir("dir-" + counter++, dirURI);
+ putDir.setDefaultName(project.getIndexFile());
+ putDir.setVerbosity(Verbosity.ALL);
+ putDir.setMaxRetries(maxRetries);
+ for (String filename: files) {
+ FileEntry fileEntry = createFileEntry(filename, edition, containerFiles);
+ if (fileEntry != null) {
+ putDir.addFileEntry(fileEntry);
+ }
+ }
+
+ /* start request */
+ try {
+ client.execute(putDir);
+ } catch (IOException ioe1) {
+ fireProjectInsertFinished(false, ioe1);
+ return;
+ }
+
+ /* parse progress and success messages */
+ boolean success = true;
+ boolean finished = false;
+ boolean disconnected = false;
+ while (!finished) {
+ Message message = client.readMessage();
+ finished = (message == null) && (disconnected = client.isDisconnected());
+ if (debug) {
+ System.out.println(message);
+ }
+ if (!finished) {
+ String messageName = message.getName();
+ if ("SimpleProgress".equals(messageName)) {
+ int total = Integer.parseInt(message.get("Total"));
+ int succeeded = Integer.parseInt(message.get("Succeeded"));
+ int fatal = Integer.parseInt(message.get("FatallyFailed"));
+ int failed = Integer.parseInt(message.get("Failed"));
+ boolean finalized = Boolean.parseBoolean(message.get("FinalizedTotal"));
+ fireProjectInsertProgress(succeeded, failed, fatal, total, finalized);
+ }
+ success = "PutSuccessful".equals(messageName);
+ finished = success || "PutFailed".equals(messageName);
+ }
+ }
+
+ /* post-insert work */
+ fireProjectInsertFinished(success, disconnected ? new IOException("Connection terminated") : null);
+ if (success) {
+ if (project instanceof EditionProject) {
+ ((EditionProject) project).setEdition(edition + 1);
+ }
+ }
+ }
+
+ //
+ // INTERFACE FileScannerListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void fileScannerFinished(FileScanner fileScanner) {
+ if (!fileScanner.isError()) {
+ new Thread(this).start();
+ } else {
+ fireProjectInsertFinished(false, null);
+ }
+ fileScanner.removeFileScannerListener(this);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.i18n.I18n;
+
+public class FileScanner implements Runnable {
+
+ private final List<FileScannerListener> fileScannerListeners = new ArrayList<FileScannerListener>();
+ private final Project project;
+ private List<String> files;
+ private boolean error = false;
+
+ public FileScanner(Project project) {
+ this.project = project;
+ }
+
+ public void addFileScannerListener(FileScannerListener fileScannerListener) {
+ fileScannerListeners.add(fileScannerListener);
+ }
+
+ public void removeFileScannerListener(FileScannerListener fileScannerListener) {
+ fileScannerListeners.remove(fileScannerListener);
+ }
+
+ protected void fireFileScannerFinished() {
+ for (FileScannerListener fileScannerListener: new ArrayList<FileScannerListener>(fileScannerListeners)) {
+ fileScannerListener.fileScannerFinished(this);
+ }
+ }
+
+ public void run() {
+ files = new ArrayList<String>();
+ error = false;
+ try {
+ scanFiles(new File(project.getLocalPath()), files);
+ Collections.sort(files);
+ } catch (IOException ioe1) {
+ error = true;
+ }
+ fireFileScannerFinished();
+ }
+
+ public boolean isError() {
+ return error;
+ }
+
+ public List<String> getFiles() {
+ return files;
+ }
+
+ private void scanFiles(File rootDir, List<String> fileList) throws IOException {
+ File[] files = rootDir.listFiles(new FileFilter() {
+
+ public boolean accept(File file) {
+ return !file.isHidden();
+ }
+ });
+ if (files == null) {
+ throw new IOException(I18n.getMessage("jsite.file-scanner.can-not-read-directory"));
+ }
+ for (File file: files) {
+ if (file.isDirectory()) {
+ scanFiles(file, fileList);
+ continue;
+ }
+ String filename = project.shortenFilename(file);
+ fileList.add(filename);
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.util.EventListener;
+
+public interface FileScannerListener extends EventListener {
+
+ public void fileScannerFinished(FileScanner fileScanner);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite-0.7 -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.util.EventListener;
+
+import de.todesbaum.jsite.application.Node;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: NodeManagerListener.java 418 2006-03-29 17:49:16Z bombe $
+ */
+public interface NodeManagerListener extends EventListener {
+
+ public void nodesUpdated(Node[] nodes);
+
+}
--- /dev/null
+/*
+ * jSite-0.7 -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import de.todesbaum.jsite.application.Node;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.util.swing.TLabel;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: NodeManagerPage.java 418 2006-03-29 17:49:16Z bombe $
+ */
+public class NodeManagerPage extends TWizardPage implements ListSelectionListener, DocumentListener, ChangeListener {
+
+ private List<NodeManagerListener> nodeManagerListeners = new ArrayList<NodeManagerListener>();
+ private TWizard wizard;
+
+ private Action addNodeAction;
+ private Action deleteNodeAction;
+ private DefaultListModel nodeListModel;
+ private JList nodeList;
+ private JTextField nodeNameTextField;
+ private JTextField nodeHostnameTextField;
+ private JSpinner nodePortSpinner;
+
+ public NodeManagerPage() {
+ super();
+ pageInit();
+ setHeading(I18n.getMessage("jsite.node-manager.heading"));
+ setDescription(I18n.getMessage("jsite.node-manager.description"));
+ }
+
+ public void addNodeManagerListener(NodeManagerListener nodeManagerListener) {
+ nodeManagerListeners.add(nodeManagerListener);
+ }
+
+ public void removeNodeManagerListener(NodeManagerListener nodeManagerListener) {
+ nodeManagerListeners.remove(nodeManagerListener);
+ }
+
+ protected void fireNodesUpdated(Node[] nodes) {
+ for (NodeManagerListener nodeManagerListener: nodeManagerListeners) {
+ nodeManagerListener.nodesUpdated(nodes);
+ }
+ }
+
+ private void createActions() {
+ addNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.add-node")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ addNode();
+ }
+ };
+
+ deleteNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.delete-node")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ deleteNode();
+ }
+ };
+ deleteNodeAction.setEnabled(false);
+ }
+
+ private void pageInit() {
+ createActions();
+ nodeListModel = new DefaultListModel();
+ nodeList = new JList(nodeListModel);
+ nodeList.setName("node-list");
+ nodeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ nodeList.addListSelectionListener(this);
+ nodeList.setPreferredSize(new Dimension(250, -1));
+
+ nodeNameTextField = new JTextField("");
+ nodeNameTextField.getDocument().putProperty("Name", "node-name");
+ nodeNameTextField.getDocument().addDocumentListener(this);
+ nodeNameTextField.setEnabled(false);
+
+ nodeHostnameTextField = new JTextField("localhost");
+ nodeHostnameTextField.getDocument().putProperty("Name", "node-hostname");
+ nodeHostnameTextField.getDocument().addDocumentListener(this);
+ nodeHostnameTextField.setEnabled(false);
+
+ nodePortSpinner = new JSpinner(new SpinnerNumberModel(9481, 1, 65535, 1));
+ nodePortSpinner.setName("node-port");
+ nodePortSpinner.addChangeListener(this);
+ nodePortSpinner.setEnabled(false);
+
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
+ buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12));
+ buttonPanel.add(new JButton(addNodeAction));
+ buttonPanel.add(new JButton(deleteNodeAction));
+
+ JPanel centerPanel = new JPanel(new BorderLayout());
+ JPanel nodeInformationPanel = new JPanel(new GridBagLayout());
+ centerPanel.add(nodeInformationPanel, BorderLayout.PAGE_START);
+ nodeInformationPanel.add(buttonPanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ nodeInformationPanel.add(new JLabel("<html><b>" + I18n.getMessage("jsite.node-manager.node-information") + "</b></html>"), new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
+ nodeInformationPanel.add(new TLabel(I18n.getMessage("jsite.node-manager.name"), KeyEvent.VK_N, nodeNameTextField), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ nodeInformationPanel.add(nodeNameTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ nodeInformationPanel.add(new TLabel(I18n.getMessage("jsite.node-manager.hostname"), KeyEvent.VK_H, nodeHostnameTextField), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ nodeInformationPanel.add(nodeHostnameTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ nodeInformationPanel.add(new TLabel(I18n.getMessage("jsite.node-manager.port"), KeyEvent.VK_P, nodePortSpinner), new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ nodeInformationPanel.add(nodePortSpinner, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0));
+
+ setLayout(new BorderLayout(12, 12));
+ add(new JScrollPane(nodeList), BorderLayout.LINE_START);
+ add(centerPanel, BorderLayout.CENTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ this.wizard = wizard;
+ wizard.setNextEnabled(nodeListModel.getSize() > 0);
+ }
+
+ public void setNodes(Node[] nodes) {
+ nodeListModel.clear();
+ for (Node node: nodes) {
+ nodeListModel.addElement(node);
+ }
+ nodeList.repaint();
+ fireNodesUpdated(nodes);
+ }
+
+ public Node[] getNodes() {
+ Node[] returnNodes = new Node[nodeListModel.getSize()];
+ for (int nodeIndex = 0, nodeCount = nodeListModel.getSize(); nodeIndex < nodeCount; nodeIndex++) {
+ returnNodes[nodeIndex] = (Node) nodeListModel.get(nodeIndex);
+ }
+ return returnNodes;
+ }
+
+ private Node getSelectedNode() {
+ return (Node) nodeList.getSelectedValue();
+ }
+
+ private void updateTextField(DocumentEvent documentEvent) {
+ Node node = getSelectedNode();
+ if (node == null) {
+ return;
+ }
+ Document document = documentEvent.getDocument();
+ String documentText = null;
+ try {
+ documentText = document.getText(0, document.getLength());
+ } catch (BadLocationException ble1) {
+ }
+ if (documentText == null) {
+ return;
+ }
+ String documentName = (String) document.getProperty("Name");
+ if ("node-name".equals(documentName)) {
+ node.setName(documentText);
+ nodeList.repaint();
+ fireNodesUpdated(getNodes());
+ } else if ("node-hostname".equals(documentName)) {
+ node.setHostname(documentText);
+ nodeList.repaint();
+ }
+ }
+
+ //
+ // ACTIONS
+ //
+
+ protected void addNode() {
+ Node node = new Node("localhost", 9481, I18n.getMessage("jsite.node-manager.new-node"));
+ nodeListModel.addElement(node);
+ wizard.setNextEnabled(true);
+ fireNodesUpdated(getNodes());
+ }
+
+ protected void deleteNode() {
+ Node node = getSelectedNode();
+ if (node == null) {
+ return;
+ }
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.node-manager.delete-node.warning"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) {
+ return;
+ }
+ nodeListModel.removeElement(node);
+ nodeList.repaint();
+ fireNodesUpdated(getNodes());
+ wizard.setNextEnabled(nodeListModel.size() > 0);
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void valueChanged(ListSelectionEvent e) {
+ Object source = e.getSource();
+ if (source instanceof JList) {
+ JList sourceList = (JList) source;
+ if ("node-list".equals(sourceList.getName())) {
+ Node node = (Node) sourceList.getSelectedValue();
+ boolean enabled = (node != null);
+ nodeNameTextField.setEnabled(enabled);
+ nodeHostnameTextField.setEnabled(enabled);
+ nodePortSpinner.setEnabled(enabled);
+ deleteNodeAction.setEnabled(enabled);
+ if (enabled) {
+ nodeNameTextField.setText(node.getName());
+ nodeHostnameTextField.setText(node.getHostname());
+ nodePortSpinner.setValue(node.getPort());
+ } else {
+ nodeNameTextField.setText("");
+ nodeHostnameTextField.setText("localhost");
+ nodePortSpinner.setValue(9481);
+ }
+ }
+ }
+ }
+
+ //
+ // INTERFACE DocumentListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void insertUpdate(DocumentEvent e) {
+ updateTextField(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeUpdate(DocumentEvent e) {
+ updateTextField(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changedUpdate(DocumentEvent e) {
+ updateTextField(e);
+ }
+
+ //
+ // INTERFACE ChangeListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateChanged(ChangeEvent e) {
+ Object source = e.getSource();
+ Node selectedNode = getSelectedNode();
+ if (selectedNode == null) {
+ return;
+ }
+ if (source instanceof JSpinner) {
+ JSpinner sourceSpinner = (JSpinner) source;
+ if ("node-port".equals(sourceSpinner.getName())) {
+ selectedNode.setPort((Integer) sourceSpinner.getValue());
+ nodeList.repaint();
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import de.todesbaum.jsite.application.EditionProject;
+import de.todesbaum.jsite.application.FileOption;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.util.mime.DefaultMIMETypes;
+import de.todesbaum.util.swing.TLabel;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ProjectFilesPage.java 404 2006-03-26 02:11:03Z bombe $
+ */
+public class ProjectFilesPage extends TWizardPage implements ActionListener, ListSelectionListener, DocumentListener, FileScannerListener, ChangeListener {
+
+ protected TWizard wizard;
+
+ protected Project project;
+
+ private Action scanAction;
+ private Action editContainerAction;
+ private Action addContainerAction;
+ private Action deleteContainerAction;
+
+ protected JList projectFileList;
+ private JCheckBox defaultFileCheckBox;
+ private JCheckBox fileOptionsInsertCheckBox;
+ private JTextField fileOptionsCustomKeyTextField;
+ private JComboBox fileOptionsMIMETypeComboBox;
+ protected DefaultComboBoxModel containerComboBoxModel;
+ private JComboBox fileOptionsContainerComboBox;
+ private JSpinner replaceEditionRangeSpinner;
+ private JCheckBox replacementCheckBox;
+
+ public ProjectFilesPage() {
+ super();
+ pageInit();
+ }
+
+ private void pageInit() {
+ createActions();
+ setLayout(new BorderLayout(12, 12));
+ add(createProjectFilesPanel(), BorderLayout.CENTER);
+ }
+
+ private void createActions() {
+ scanAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.rescan")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionScan();
+ }
+ };
+ scanAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
+ scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip"));
+
+ addContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.add-container")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionAddContainer();
+ }
+ };
+ addContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.add-container.tooltip"));
+ addContainerAction.setEnabled(false);
+
+ editContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.edit-container")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionEditContainer();
+ }
+ };
+ editContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.edit-container.tooltip"));
+ editContainerAction.setEnabled(false);
+
+ deleteContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.delete-container")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionDeleteContainer();
+ }
+ };
+ deleteContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.delete-container.tooltip"));
+ deleteContainerAction.setEnabled(false);
+ }
+
+ public void pageAdded(TWizard wizard) {
+ this.wizard = wizard;
+ actionScan();
+ }
+
+ private JComponent createProjectFilesPanel() {
+ JPanel projectFilesPanel = new JPanel(new BorderLayout(12, 12));
+
+ projectFileList = new JList();
+ projectFileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ projectFileList.setMinimumSize(new Dimension(250, projectFileList.getPreferredSize().height));
+ projectFileList.addListSelectionListener(this);
+
+ projectFilesPanel.add(new JScrollPane(projectFileList), BorderLayout.CENTER);
+
+ JPanel fileOptionsAlignmentPanel = new JPanel(new BorderLayout(12, 12));
+ projectFilesPanel.add(fileOptionsAlignmentPanel, BorderLayout.PAGE_END);
+ JPanel fileOptionsPanel = new JPanel(new GridBagLayout());
+ fileOptionsAlignmentPanel.add(fileOptionsPanel, BorderLayout.PAGE_START);
+
+ fileOptionsPanel.add(new JButton(scanAction), new GridBagConstraints(0, 0, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+
+ fileOptionsPanel.add(new JLabel("<html><b>" + I18n.getMessage("jsite.project-files.file-options") + "</b></html>"), new GridBagConstraints(0, 1, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
+
+ defaultFileCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.default"));
+ defaultFileCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.default.tooltip"));
+ defaultFileCheckBox.setName("default-file");
+ defaultFileCheckBox.addActionListener(this);
+ defaultFileCheckBox.setEnabled(false);
+
+ fileOptionsPanel.add(defaultFileCheckBox, new GridBagConstraints(0, 2, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+
+ fileOptionsInsertCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.insert"), true);
+ fileOptionsInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert.tooltip"));
+ fileOptionsInsertCheckBox.setName("insert");
+ fileOptionsInsertCheckBox.setMnemonic(KeyEvent.VK_I);
+ fileOptionsInsertCheckBox.addActionListener(this);
+ fileOptionsInsertCheckBox.setEnabled(false);
+
+ fileOptionsPanel.add(fileOptionsInsertCheckBox, new GridBagConstraints(0, 3, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ fileOptionsCustomKeyTextField = new JTextField(45);
+ fileOptionsCustomKeyTextField.setToolTipText(I18n.getMessage("jsite.project-files.custom-key.tooltip"));
+ fileOptionsCustomKeyTextField.setEnabled(false);
+ fileOptionsCustomKeyTextField.getDocument().addDocumentListener(this);
+
+ fileOptionsPanel.add(new TLabel(I18n.getMessage("jsite.project-files.custom-key"), KeyEvent.VK_K, fileOptionsCustomKeyTextField), new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ fileOptionsPanel.add(fileOptionsCustomKeyTextField, new GridBagConstraints(1, 4, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ fileOptionsMIMETypeComboBox = new JComboBox(DefaultMIMETypes.getAllMIMETypes());
+ fileOptionsMIMETypeComboBox.setToolTipText(I18n.getMessage("jsite.project-files.mime-type.tooltip"));
+ fileOptionsMIMETypeComboBox.setName("project-files.mime-type");
+ fileOptionsMIMETypeComboBox.addActionListener(this);
+ fileOptionsMIMETypeComboBox.setEnabled(false);
+
+ fileOptionsPanel.add(new TLabel(I18n.getMessage("jsite.project-files.mime-type"), KeyEvent.VK_M, fileOptionsMIMETypeComboBox), new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ fileOptionsPanel.add(fileOptionsMIMETypeComboBox, new GridBagConstraints(1, 5, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ containerComboBoxModel = new DefaultComboBoxModel();
+ fileOptionsContainerComboBox = new JComboBox(containerComboBoxModel);
+ fileOptionsContainerComboBox.setToolTipText(I18n.getMessage("jsite.project-files.container.tooltip"));
+ fileOptionsContainerComboBox.setName("project-files.container");
+ fileOptionsContainerComboBox.addActionListener(this);
+ fileOptionsContainerComboBox.setEnabled(false);
+
+ fileOptionsPanel.add(new TLabel(I18n.getMessage("jsite.project-files.container"), KeyEvent.VK_C, fileOptionsContainerComboBox), new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ fileOptionsPanel.add(fileOptionsContainerComboBox, new GridBagConstraints(1, 6, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ fileOptionsPanel.add(new JButton(addContainerAction), new GridBagConstraints(2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ fileOptionsPanel.add(new JButton(editContainerAction), new GridBagConstraints(3, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ fileOptionsPanel.add(new JButton(deleteContainerAction), new GridBagConstraints(4, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ JPanel fileOptionsReplacementPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 6, 6));
+ fileOptionsReplacementPanel.setBorder(new EmptyBorder(-6, -6, -6, -6));
+
+ replacementCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.replacement"));
+ replacementCheckBox.setName("project-files.replace-edition");
+ replacementCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.replacement.tooltip"));
+ replacementCheckBox.addActionListener(this);
+ replacementCheckBox.setEnabled(false);
+ fileOptionsReplacementPanel.add(replacementCheckBox);
+
+ replaceEditionRangeSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
+ replaceEditionRangeSpinner.setName("project-files.replace-edition-range");
+ replaceEditionRangeSpinner.setToolTipText(I18n.getMessage("jsite.project-files.replacement.edition-range.tooltip"));
+ replaceEditionRangeSpinner.addChangeListener(this);
+ replaceEditionRangeSpinner.setEnabled(false);
+ fileOptionsReplacementPanel.add(new JLabel(I18n.getMessage("jsite.project-files.replacement.edition-range")));
+ fileOptionsReplacementPanel.add(replaceEditionRangeSpinner);
+
+ fileOptionsPanel.add(fileOptionsReplacementPanel, new GridBagConstraints(0, 7, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+
+ return projectFilesPanel;
+ }
+
+ public void setProject(Project project) {
+ this.project = project;
+ setHeading(MessageFormat.format(I18n.getMessage("jsite.project-files.heading"), project.getName()));
+ setDescription(I18n.getMessage("jsite.project-files.description"));
+ }
+
+ private List<String> getProjectFiles() {
+ List<String> files = new ArrayList<String>();
+ for (int index = 0, size = projectFileList.getModel().getSize(); index < size; index++) {
+ files.add((String) projectFileList.getModel().getElementAt(index));
+ }
+ return files;
+ }
+
+ protected void rebuildContainerComboBox() {
+ /* scan files for containers */
+ List<String> files = getProjectFiles();
+ List<String> containers = new ArrayList<String>(); // ComboBoxModel
+ // sucks. No
+ // contains()!
+ containers.add("");
+ for (String filename: files) {
+ String container = project.getFileOption(filename).getContainer();
+ if (!containers.contains(container)) {
+ containers.add(container);
+ }
+ }
+ Collections.sort(containers);
+ containerComboBoxModel.removeAllElements();
+ for (String container: containers) {
+ containerComboBoxModel.addElement(container);
+ }
+ }
+
+ //
+ // ACTIONS
+ //
+
+ protected void actionScan() {
+ projectFileList.clearSelection();
+ projectFileList.setListData(new Object[0]);
+
+ wizard.setNextEnabled(false);
+ wizard.setPreviousEnabled(false);
+ wizard.setQuitEnabled(false);
+
+ FileScanner fileScanner = new FileScanner(project);
+ fileScanner.addFileScannerListener(this);
+ new Thread(fileScanner).start();
+ }
+
+ protected void actionAddContainer() {
+ String containerName = JOptionPane.showInputDialog(wizard, I18n.getMessage("jsite.project-files.action.add-container.message") + ":", null, JOptionPane.INFORMATION_MESSAGE);
+ if (containerName == null) {
+ return;
+ }
+ containerName = containerName.trim();
+ String filename = (String) projectFileList.getSelectedValue();
+ FileOption fileOption = project.getFileOption(filename);
+ fileOption.setContainer(containerName);
+ rebuildContainerComboBox();
+ fileOptionsContainerComboBox.setSelectedItem(containerName);
+ }
+
+ protected void actionEditContainer() {
+ String selectedFilename = (String) projectFileList.getSelectedValue();
+ FileOption fileOption = project.getFileOption(selectedFilename);
+ String oldContainerName = fileOption.getContainer();
+ String containerName = JOptionPane.showInputDialog(wizard, I18n.getMessage("jsite.project-files.action.edit-container.message") + ":", oldContainerName);
+ if (containerName == null) {
+ return;
+ }
+ if (containerName.equals("")) {
+ fileOption.setContainer("");
+ fileOptionsContainerComboBox.setSelectedItem("");
+ return;
+ }
+ List<String> files = getProjectFiles();
+ for (String filename: files) {
+ fileOption = project.getFileOption(filename);
+ if (fileOption.getContainer().equals(oldContainerName)) {
+ fileOption.setContainer(containerName);
+ }
+ }
+ rebuildContainerComboBox();
+ fileOptionsContainerComboBox.setSelectedItem(containerName);
+ }
+
+ protected void actionDeleteContainer() {
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.action.delete-container.message"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
+ String containerName = (String) fileOptionsContainerComboBox.getSelectedItem();
+ List<String> files = getProjectFiles();
+ for (String filename: files) {
+ FileOption fileOption = project.getFileOption(filename);
+ if (fileOption.getContainer().equals(containerName)) {
+ fileOption.setContainer("");
+ }
+ }
+ fileOptionsContainerComboBox.setSelectedItem("");
+ }
+ }
+
+ public void fileScannerFinished(FileScanner fileScanner) {
+ final boolean error = fileScanner.isError();
+ if (!error) {
+ final List<String> files = fileScanner.getFiles();
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ projectFileList.setListData(files.toArray(new String[files.size()]));
+ projectFileList.clearSelection();
+ rebuildContainerComboBox();
+ }
+ });
+ } else {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.scan-error"), null, JOptionPane.ERROR_MESSAGE);
+ }
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ wizard.setPreviousEnabled(true);
+ wizard.setNextEnabled(!error);
+ wizard.setQuitEnabled(true);
+ }
+ });
+ }
+
+ //
+ // INTERFACE ActionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void actionPerformed(ActionEvent actionEvent) {
+ String filename = (String) projectFileList.getSelectedValue();
+ if (filename == null) {
+ return;
+ }
+ FileOption fileOption = project.getFileOption(filename);
+ Object source = actionEvent.getSource();
+ if (source instanceof JCheckBox) {
+ JCheckBox checkBox = (JCheckBox) source;
+ if ("default-file".equals(checkBox.getName())) {
+ if (checkBox.isSelected()) {
+ project.setIndexFile(filename);
+ } else {
+ project.setIndexFile(null);
+ }
+ } else if ("insert".equals(checkBox.getName())) {
+ boolean isInsert = checkBox.isSelected();
+ fileOptionsCustomKeyTextField.setEnabled(!isInsert);
+ fileOption.setInsert(isInsert);
+ if (!isInsert) {
+ fileOptionsContainerComboBox.setSelectedItem("");
+ }
+ } else if ("project-files.replace-edition".equals(checkBox.getName())) {
+ boolean replaceEdition = checkBox.isSelected();
+ fileOption.setReplaceEdition(replaceEdition);
+ replaceEditionRangeSpinner.setEnabled(replaceEdition);
+ }
+ } else if (source instanceof JComboBox) {
+ JComboBox comboBox = (JComboBox) source;
+ if ("project-files.mime-type".equals(comboBox.getName())) {
+ fileOption.setMimeType((String) comboBox.getSelectedItem());
+ } else if ("project-files.container".equals(comboBox.getName())) {
+ String containerName = (String) comboBox.getSelectedItem();
+ fileOption.setContainer(containerName);
+ boolean enabled = !"".equals(containerName);
+ editContainerAction.setEnabled(enabled);
+ deleteContainerAction.setEnabled(enabled);
+ if (enabled) {
+ fileOptionsInsertCheckBox.setSelected(true);
+ }
+ }
+ }
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void valueChanged(ListSelectionEvent e) {
+ String filename = (String) projectFileList.getSelectedValue();
+ boolean enabled = filename != null;
+ boolean insert = fileOptionsInsertCheckBox.isSelected();
+ defaultFileCheckBox.setEnabled(enabled);
+ fileOptionsInsertCheckBox.setEnabled(enabled);
+ fileOptionsCustomKeyTextField.setEnabled(enabled && !insert);
+ fileOptionsMIMETypeComboBox.setEnabled(enabled);
+ fileOptionsContainerComboBox.setEnabled(enabled);
+ addContainerAction.setEnabled(enabled);
+ editContainerAction.setEnabled(enabled);
+ deleteContainerAction.setEnabled(enabled);
+ replacementCheckBox.setEnabled(enabled && insert && (project instanceof EditionProject));
+ if (filename != null) {
+ FileOption fileOption = project.getFileOption(filename);
+ defaultFileCheckBox.setSelected(filename.equals(project.getIndexFile()));
+ fileOptionsInsertCheckBox.setSelected(fileOption.isInsert());
+ fileOptionsCustomKeyTextField.setText(fileOption.getCustomKey());
+ fileOptionsMIMETypeComboBox.getModel().setSelectedItem(fileOption.getMimeType());
+ fileOptionsContainerComboBox.setSelectedItem(fileOption.getContainer());
+ replacementCheckBox.setSelected(fileOption.getReplaceEdition());
+ replaceEditionRangeSpinner.setValue(fileOption.getEditionRange());
+ replaceEditionRangeSpinner.setEnabled(fileOption.getReplaceEdition());
+ } else {
+ defaultFileCheckBox.setSelected(false);
+ fileOptionsInsertCheckBox.setSelected(true);
+ fileOptionsCustomKeyTextField.setText("CHK@");
+ fileOptionsMIMETypeComboBox.getModel().setSelectedItem(DefaultMIMETypes.DEFAULT_MIME_TYPE);
+ fileOptionsContainerComboBox.setSelectedItem("");
+ replacementCheckBox.setSelected(false);
+ replaceEditionRangeSpinner.setValue(0);
+ }
+ }
+
+ //
+ // INTERFACE DocumentListener
+ //
+
+ private void processDocumentUpdate(DocumentEvent documentEvent) {
+ String filename = (String) projectFileList.getSelectedValue();
+ if (filename == null)
+ return;
+ FileOption fileOption = project.getFileOption(filename);
+ Document document = documentEvent.getDocument();
+ try {
+ String text = document.getText(0, document.getLength());
+ fileOption.setCustomKey(text);
+ } catch (BadLocationException ble1) {
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changedUpdate(DocumentEvent documentEvent) {
+ processDocumentUpdate(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void insertUpdate(DocumentEvent documentEvent) {
+ processDocumentUpdate(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeUpdate(DocumentEvent documentEvent) {
+ processDocumentUpdate(documentEvent);
+ }
+
+ //
+ // INTERFACE ChangeListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateChanged(ChangeEvent changeEvent) {
+ String filename = (String) projectFileList.getSelectedValue();
+ if (filename == null)
+ return;
+ FileOption fileOption = project.getFileOption(filename);
+ Object source = changeEvent.getSource();
+ if (source instanceof JSpinner) {
+ JSpinner spinner = (JSpinner) source;
+ fileOption.setEditionRange((Integer) spinner.getValue());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import de.todesbaum.jsite.application.EditionProject;
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.InsertListener;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.application.ProjectInserter;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ProjectInsertPage.java 408 2006-03-29 09:31:10Z bombe $
+ */
+public class ProjectInsertPage extends TWizardPage implements InsertListener {
+
+ protected TWizard wizard;
+ protected ProjectInserter projectInserter;
+
+ protected JTextField requestURITextField;
+ protected JLabel startTimeLabel;
+ protected JProgressBar progressBar;
+ protected long startTime;
+
+ public ProjectInsertPage() {
+ super();
+ pageInit();
+ setHeading(I18n.getMessage("jsite.insert.heading"));
+ setDescription(I18n.getMessage("jsite.insert.description"));
+ projectInserter = new ProjectInserter();
+ projectInserter.addInsertListener(this);
+ }
+
+ private void pageInit() {
+ setLayout(new BorderLayout(12, 12));
+ add(createProjectInsertPanel(), BorderLayout.CENTER);
+ }
+
+ private JComponent createProjectInsertPanel() {
+ JComponent projectInsertPanel = new JPanel(new GridBagLayout());
+
+ requestURITextField = new JTextField();
+ requestURITextField.setEditable(false);
+ requestURITextField.setBackground(getBackground());
+ requestURITextField.setBorder(null);
+
+ startTimeLabel = new JLabel();
+
+ progressBar = new JProgressBar(0, 1);
+ progressBar.setStringPainted(true);
+ progressBar.setValue(0);
+
+ projectInsertPanel.add(new JLabel("<html><b>" + I18n.getMessage("jsite.insert.project-information") + "</b></html>"), new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ projectInsertPanel.add(new JLabel(I18n.getMessage("jsite.insert.request-uri") + ":"), new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ projectInsertPanel.add(requestURITextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ projectInsertPanel.add(new JLabel(I18n.getMessage("jsite.insert.start-time") + ":"), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ projectInsertPanel.add(startTimeLabel, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ projectInsertPanel.add(new JLabel(I18n.getMessage("jsite.insert.progress") + ":"), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ projectInsertPanel.add(progressBar, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ return projectInsertPanel;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ this.wizard = wizard;
+ wizard.setPreviousEnabled(false);
+ wizard.setNextEnabled(false);
+ wizard.setQuitEnabled(false);
+ progressBar.setValue(0);
+ projectInserter.start();
+ }
+
+ /**
+ * @param debug
+ * The debug to set.
+ */
+ public void setDebug(boolean debug) {
+ projectInserter.setDebug(debug);
+ }
+
+ /**
+ * @param project
+ * The project to set.
+ */
+ public void setProject(final Project project) {
+ projectInserter.setProject(project);
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ StringBuffer uriBuffer = new StringBuffer();
+ uriBuffer.append(project.getRequestURI());
+ uriBuffer.append(project.getPath());
+ if (project instanceof EditionProject) {
+ uriBuffer.append('-').append(((EditionProject) project).getEdition());
+ }
+ uriBuffer.append('/');
+ requestURITextField.setText(uriBuffer.toString());
+ }
+ });
+ }
+
+ public void setFreenetInterface(Freenet7Interface freenetInterface) {
+ projectInserter.setFreenetInterface(freenetInterface);
+ }
+
+ //
+ // INTERFACE InsertListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertStarted(final Project project) {
+ startTime = System.currentTimeMillis();
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ startTimeLabel.setText(DateFormat.getDateTimeInstance().format(new Date(startTime)));
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertProgress(Project project, final int succeeded, final int failed, final int fatal, final int total, final boolean finalized) {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ progressBar.setMaximum(total);
+ progressBar.setValue(succeeded + failed + fatal);
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertFinished(Project project, boolean success, Throwable cause) {
+ if (success) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.inserted"), null, JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ if (cause == null) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.insert-failed"), null, JOptionPane.ERROR_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.insert.insert-failed-with-cause"), cause.getMessage()), null, JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ wizard.setNextEnabled(true);
+ wizard.setQuitEnabled(true);
+ }
+ });
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.JSpinner.NumberEditor;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import de.todesbaum.jsite.application.EditionProject;
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.util.swing.SortedListModel;
+import de.todesbaum.util.swing.TLabel;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ProjectPage.java 418 2006-03-29 17:49:16Z bombe $
+ */
+public class ProjectPage extends TWizardPage implements ListSelectionListener, ChangeListener, DocumentListener {
+
+ private Freenet7Interface freenetInterface;
+
+ private Action projectLocalPathBrowseAction;
+ private Action projectAddAction;
+ private Action projectDeleteAction;
+ private Action projectCloneAction;
+
+ private JFileChooser pathChooser;
+ private SortedListModel projectListModel;
+ private JList projectList;
+ private JTextField projectNameTextField;
+ private JTextField projectDescriptionTextField;
+ private JTextField projectLocalPathTextField;
+ private JTextField projectPublicKeyTextField;
+ private JTextField projectPrivateKeyTextField;
+ private JTextField projectPathTextField;
+ private JSpinner projectEditionSpinner;
+
+ public ProjectPage() {
+ super();
+ setLayout(new BorderLayout(12, 12));
+ dialogInit();
+ setHeading(I18n.getMessage("jsite.project.heading"));
+ setDescription(I18n.getMessage("jsite.project.description"));
+ }
+
+ protected void dialogInit() {
+ createActions();
+
+ pathChooser = new JFileChooser();
+ projectListModel = new SortedListModel();
+ projectList = new JList(projectListModel);
+ projectList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ projectList.addListSelectionListener(this);
+ projectList.setPreferredSize(new Dimension(150, projectList.getPreferredSize().height));
+
+ add(new JScrollPane(projectList), BorderLayout.LINE_START);
+ add(createInformationPanel(), BorderLayout.CENTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ super.pageAdded(wizard);
+ projectList.clearSelection();
+ wizard.setNextEnabled(false);
+ }
+
+ /**
+ */
+ public void addListSelectionListener(ListSelectionListener listener) {
+ projectList.addListSelectionListener(listener);
+ }
+
+ /**
+ */
+ public void removeListSelectionListener(ListSelectionListener listener) {
+ projectList.removeListSelectionListener(listener);
+ }
+
+ private void createActions() {
+ projectLocalPathBrowseAction = new AbstractAction(I18n.getMessage("jsite.project.action.browse")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionLocalPathBrowse();
+ }
+ };
+ projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
+ projectLocalPathBrowseAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_B);
+ projectLocalPathBrowseAction.setEnabled(false);
+
+ projectAddAction = new AbstractAction(I18n.getMessage("jsite.project.action.add-project")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionAdd();
+ }
+ };
+ projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
+ projectAddAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
+
+ projectDeleteAction = new AbstractAction(I18n.getMessage("jsite.project.action.delete-project")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionDelete();
+ }
+ };
+ projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
+ projectDeleteAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
+ projectDeleteAction.setEnabled(false);
+
+ projectCloneAction = new AbstractAction(I18n.getMessage("jsite.project.action.clone-project")) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionClone();
+ }
+ };
+ projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
+ projectCloneAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L);
+ projectCloneAction.setEnabled(false);
+ }
+
+ private JComponent createInformationPanel() {
+ JPanel informationPanel = new JPanel(new BorderLayout(12, 12));
+
+ JPanel informationTable = new JPanel(new GridBagLayout());
+
+ JPanel functionButtons = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
+ functionButtons.setBorder(new EmptyBorder(-12, -12, -12, -12));
+ functionButtons.add(new JButton(projectAddAction));
+ functionButtons.add(new JButton(projectDeleteAction));
+ functionButtons.add(new JButton(projectCloneAction));
+
+ informationPanel.add(functionButtons, BorderLayout.PAGE_START);
+ informationPanel.add(informationTable, BorderLayout.CENTER);
+
+ informationTable.add(new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>"), new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+
+ projectNameTextField = new JTextField();
+ projectNameTextField.getDocument().putProperty("name", "project.name");
+ projectNameTextField.getDocument().addDocumentListener(this);
+ projectNameTextField.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.name") + ":", KeyEvent.VK_N, projectNameTextField), new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectNameTextField, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectDescriptionTextField = new JTextField();
+ projectDescriptionTextField.getDocument().putProperty("name", "project.description");
+ projectDescriptionTextField.getDocument().addDocumentListener(this);
+ projectDescriptionTextField.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.description") + ":", KeyEvent.VK_D, projectDescriptionTextField), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectDescriptionTextField, new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectLocalPathTextField = new JTextField();
+ projectLocalPathTextField.getDocument().putProperty("name", "project.localpath");
+ projectLocalPathTextField.getDocument().addDocumentListener(this);
+ projectLocalPathTextField.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.local-path") + ":", KeyEvent.VK_L, projectLocalPathTextField), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectLocalPathTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ informationTable.add(new JButton(projectLocalPathBrowseAction), new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ informationTable.add(new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>"), new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
+
+ projectPublicKeyTextField = new JTextField(27);
+ projectPublicKeyTextField.getDocument().putProperty("name", "project.publickey");
+ projectPublicKeyTextField.getDocument().addDocumentListener(this);
+ projectPublicKeyTextField.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.public-key") + ":", KeyEvent.VK_U, projectPublicKeyTextField), new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectPublicKeyTextField, new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectPrivateKeyTextField = new JTextField(27);
+ projectPrivateKeyTextField.getDocument().putProperty("name", "project.privatekey");
+ projectPrivateKeyTextField.getDocument().addDocumentListener(this);
+ projectPrivateKeyTextField.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.private-key") + ":", KeyEvent.VK_R, projectPrivateKeyTextField), new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectPrivateKeyTextField, new GridBagConstraints(1, 6, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectPathTextField = new JTextField();
+ projectPathTextField.getDocument().putProperty("name", "project.path");
+ projectPathTextField.getDocument().addDocumentListener(this);
+ projectPathTextField.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.path") + ":", KeyEvent.VK_P, projectPathTextField), new GridBagConstraints(0, 7, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectPathTextField, new GridBagConstraints(1, 7, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectEditionSpinner = new JSpinner(new SpinnerNumberModel(1, 0, Integer.MAX_VALUE, 1));
+ ((NumberEditor) projectEditionSpinner.getEditor()).getTextField().setColumns(6);
+ projectEditionSpinner.setName("project.edition");
+ projectEditionSpinner.addChangeListener(this);
+ projectEditionSpinner.setEnabled(false);
+
+ informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.edition") + ":", KeyEvent.VK_E, projectEditionSpinner), new GridBagConstraints(0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectEditionSpinner, new GridBagConstraints(1, 8, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0));
+
+ return informationPanel;
+ }
+
+ public void setProjects(Project[] projects) {
+ projectListModel.clear();
+ for (Project project: projects) {
+ projectListModel.add(project);
+ }
+ }
+
+ public Project[] getProjects() {
+ return (Project[]) projectListModel.toArray(new Project[projectListModel.size()]);
+ }
+
+ /**
+ * @param freenetInterface
+ * The freenetInterface to set.
+ */
+ public void setFreenetInterface(Freenet7Interface freenetInterface) {
+ this.freenetInterface = freenetInterface;
+ }
+
+ public Project getSelectedProject() {
+ return (Project) projectList.getSelectedValue();
+ }
+
+ private void setTextField(DocumentEvent documentEvent) {
+ Document document = documentEvent.getDocument();
+ String propertyName = (String) document.getProperty("name");
+ Project project = (Project) projectList.getSelectedValue();
+ if (project == null) {
+ return;
+ }
+ try {
+ String text = document.getText(0, document.getLength()).trim();
+ if ("project.name".equals(propertyName)) {
+ project.setName(text);
+ projectList.repaint();
+ } else if ("project.description".equals(propertyName)) {
+ project.setDescription(text);
+ } else if ("project.localpath".equals(propertyName)) {
+ project.setLocalPath(text);
+ } else if ("project.privatekey".equals(propertyName)) {
+ project.setInsertURI(text);
+ } else if ("project.publickey".equals(propertyName)) {
+ project.setRequestURI(text);
+ } else if ("project.path".equals(propertyName)) {
+ project.setPath(text);
+ }
+ } catch (BadLocationException e) {
+ }
+ }
+
+ //
+ // ACTIONS
+ //
+
+ protected void actionLocalPathBrowse() {
+ Project project = (Project) projectList.getSelectedValue();
+ if (project == null)
+ return;
+ pathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ if (pathChooser.showDialog(this, I18n.getMessage("jsite.project.action.browse.choose")) == JFileChooser.APPROVE_OPTION) {
+ projectLocalPathTextField.setText(pathChooser.getSelectedFile().getPath());
+ }
+ }
+
+ protected void actionAdd() {
+ String[] keyPair = null;
+ if (!freenetInterface.hasNode()) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ try {
+ keyPair = freenetInterface.generateKeyPair();
+ } catch (IOException ioe1) {
+ JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ EditionProject newProject = new EditionProject();
+ newProject.setName(I18n.getMessage("jsite.project.new-project.name"));
+ newProject.setInsertURI(keyPair[0]);
+ newProject.setRequestURI(keyPair[1]);
+ newProject.setEdition(1);
+ projectListModel.add(newProject);
+ projectList.setSelectedIndex(projectListModel.size() - 1);
+ }
+
+ protected void actionDelete() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ if (JOptionPane.showConfirmDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.action.delete-project.confirm"), ((Project) projectList.getSelectedValue()).getName()), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
+ projectListModel.remove(selectedIndex);
+ projectList.clearSelection();
+ if (projectListModel.getSize() != 0) {
+ projectList.setSelectedIndex(Math.min(selectedIndex, projectListModel.getSize() - 1));
+ }
+ }
+ }
+ }
+
+ protected void actionClone() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ Project newProject = null;
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ if (selectedProject instanceof EditionProject) {
+ newProject = new EditionProject(selectedProject);
+ } // else { /* BUG! */ }
+ newProject.setName(MessageFormat.format(I18n.getMessage("jsite.project.action.clone-project.copy"), newProject.getName()));
+ projectListModel.add(newProject);
+ projectList.setSelectedIndex(projectListModel.indexOf(newProject));
+ }
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void valueChanged(ListSelectionEvent listSelectionEvent) {
+ int selectedRow = projectList.getSelectedIndex();
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ projectNameTextField.setEnabled(selectedRow > -1);
+ projectDescriptionTextField.setEnabled(selectedRow > -1);
+ projectLocalPathTextField.setEnabled(selectedRow > -1);
+ projectPublicKeyTextField.setEnabled(selectedRow > -1);
+ projectPrivateKeyTextField.setEnabled(selectedRow > -1);
+ projectPathTextField.setEnabled(selectedRow > -1);
+ projectEditionSpinner.setEnabled(selectedRow > -1);
+ projectLocalPathBrowseAction.setEnabled(selectedRow > -1);
+ projectDeleteAction.setEnabled(selectedRow > -1);
+ projectCloneAction.setEnabled(selectedRow > -1);
+ if (selectedRow > -1) {
+ projectNameTextField.setText(selectedProject.getName());
+ projectDescriptionTextField.setText(selectedProject.getDescription());
+ projectLocalPathTextField.setText(selectedProject.getLocalPath());
+ projectPublicKeyTextField.setText(selectedProject.getRequestURI());
+ projectPrivateKeyTextField.setText(selectedProject.getInsertURI());
+ projectPathTextField.setText(selectedProject.getPath());
+ if (selectedProject instanceof EditionProject) {
+ EditionProject editionProject = (EditionProject) selectedProject;
+ projectEditionSpinner.setValue(editionProject.getEdition());
+ }
+ } else {
+ projectNameTextField.setText("");
+ projectDescriptionTextField.setText("");
+ projectLocalPathTextField.setText("");
+ projectPublicKeyTextField.setText("");
+ projectPrivateKeyTextField.setText("");
+ projectPathTextField.setText("");
+ projectEditionSpinner.setValue(0);
+ }
+ }
+
+ //
+ // INTERFACE ChangeListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateChanged(ChangeEvent changeEvent) {
+ Object source = changeEvent.getSource();
+ if (source instanceof JSpinner) {
+ JSpinner spinner = (JSpinner) source;
+ Project currentProject = (Project) projectList.getSelectedValue();
+ if (currentProject == null) {
+ return;
+ }
+ if ("project.edition".equals(spinner.getName())) {
+ ((EditionProject) currentProject).setEdition((Integer) spinner.getValue());
+ }
+ }
+ }
+
+ //
+ // INTERFACE DocumentListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void insertUpdate(DocumentEvent documentEvent) {
+ setTextField(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeUpdate(DocumentEvent documentEvent) {
+ setTextField(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changedUpdate(DocumentEvent documentEvent) {
+ setTextField(documentEvent);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.i18n;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: I18n.java 355 2006-03-24 15:04:11Z bombe $
+ */
+public class I18n {
+
+ private static Locale currentLocale;
+
+ public static Locale getLocale() {
+ if (currentLocale == null)
+ currentLocale = Locale.getDefault();
+ return currentLocale;
+ }
+
+ public static void setLocale(Locale locale) {
+ currentLocale = locale;
+ Locale.setDefault(locale);
+ }
+
+ public static ResourceBundle getResourceBundle() {
+ return getResourceBundle(getLocale());
+ }
+
+ public static ResourceBundle getResourceBundle(Locale locale) {
+ return ResourceBundle.getBundle("de.todesbaum.jsite.i18n.jSite", locale);
+ }
+
+ public static String getMessage(String key) {
+ return getResourceBundle().getString(key);
+ }
+
+}
--- /dev/null
+#
+# jSite - a tool for uploading websites into Freenet
+# Copyright (C) 2006 David Roden
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# English language file by David Roden <droden@gmail.com>
+
+jsite.main.already-running=<html><b>jSite is already running</b><br><br>A lock file has been found that suggests that another<br>instance of jSite is already running. Running multiple instances<br>of jSite is guaranteed to break your configuration.</htm>
+
+jsite.wizard.previous=Previous
+jsite.wizard.next=Next
+jsite.wizard.quit=Quit
+
+jsite.quit.question=Do you really want to quit?
+jsite.quit.config-not-saved=<html><b>Configuration not saved</b><br><br>The configuration could not be saved.<br>Do you want to quit anyway?</html>
+
+jsite.menu.languages=Languages
+jsite.menu.language.change.restart-message=<html><b>Restart necessary</b><br><br>For language changes to take effect,<br>jSite must be restarted!</html>
+jsite.menu.language.en=English
+jsite.menu.language.de=German
+jsite.menu.nodes=Nodes
+jsite.menu.nodes.manage-nodes=Manage nodes
+jsite.menu.help=Help
+jsite.menu.help.about=About
+
+jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006 David Roden<br>Released under the GNU General Public License</html>
+
+jsite.node-manager.heading=Node Manager
+jsite.node-manager.description=Manage your nodes here.
+jsite.node-manager.node-information=Node Information
+jsite.node-manager.add-node=Add Node
+jsite.node-manager.new-node=New Node
+jsite.node-manager.delete-node=Delete Node
+jsite.node-manager.delete-node.warning=<html><b>Confirm node deletion</b><br><br>Really delete this node?</html>
+jsite.node-manager.name=Name
+jsite.node-manager.hostname=Hostname
+jsite.node-manager.port=Port
+
+jsite.insert.heading=Project insert
+jsite.insert.description=Please wait while the project is being inserted.
+jsite.insert.project-information=Project information
+jsite.insert.request-uri=Freesite
+jsite.insert.start-time=Start time
+jsite.insert.progress=Progress
+jsite.insert.insert-failed=<html><b>Insert failed</b><br><br>The insert of the project failed.<br>Some files could not be inserted.</html>
+jsite.insert.insert-failed-with-cause=<html><b>Insert failed</b><br><br>The insert of the project failed.<br>Some files could not be inserted.<br>The following error occured:<br><br><code>{0}</code></html>
+jsite.insert.inserted=<html><b>Project inserted</b><br><br>Your project was inserted successfully.</html>
+
+jsite.file-scanner.can-not-read-directory=Can not read directory
+
+jsite.project.heading=Select a Project
+jsite.project.description=Select a project to process from the list below, or create a new project.
+jsite.project.action.browse=Browse
+jsite.project.action.browse.choose=Choose
+jsite.project.action.browse.tooltip=Browse for directory
+jsite.project.action.add-project=Add project
+jsite.project.action.add-project.tooltip=Add a new project
+jsite.project.new-project.name=New Project
+jsite.project.action.delete-project=Delete project
+jsite.project.action.delete-project.tooltip=Delete a project
+jsite.project.action.delete-project.confirm=<html><b>Confirm deletion</b><br><br>The project \u201c{0}\u201d will be deleted!<br>Do you want to continue?</html>
+jsite.project.action.clone-project=Clone project
+jsite.project.action.clone-project.copy=Copy of {0}
+jsite.project.action.clone-project.tooltip=Clone the selected project
+jsite.project.project.information=Project Information
+jsite.project.project.name=Name
+jsite.project.project.description=Description
+jsite.project.project.local-path=Local path
+jsite.project.project.address=Address
+jsite.project.project.public-key=Request URI
+jsite.project.project.private-key=Insert URI
+jsite.project.project.path=Path
+jsite.project.project.edition=Edition
+jsite.project.keygen.io-error=<html><b>Node communication failure</b><br><br>Communication with the node failed<br>with the following error message:<br><br><code>{0}</code><br><br>Please make sure that you have entered<br>the correct host name and port number<br>on the "Node Settings" page.</html>
+jsite.project.warning.no-local-path=<html><b>No local path</b><br><br>You did not specify a local path for the files to insert.<br>It is not possible to continue without one.</html>
+jsite.project.warning.no-path=<html><b>No freesite path</b><br><br>You did not specify a freesite path.<br>It is not possible to continue without one.</html>
+
+jsite.project-files.heading=Project Files
+jsite.project-files.description=<html>On this page you can specify parameters for the files within the project, such as<br>externally generated keys or MIME types, if the automatic detection failed.</html>
+jsite.project-files.action.rescan=Re-scan
+jsite.project-files.action.rescan.tooltip=Re-scan the project directory for new files
+jsite.project-files.action.add-container=Add
+jsite.project-files.action.add-container.tooltip=Adds a new container to the project and this file to it
+jsite.project-files.action.add-container.message=Enter the name of the new container
+jsite.project-files.action.edit-container=Edit
+jsite.project-files.action.edit-container.tooltip=Changes the name of the container
+jsite.project-files.action.edit-container.message=Enter the new name of the container
+jsite.project-files.action.delete-container=Delete
+jsite.project-files.action.delete-container.tooltip=Deletes this container
+jsite.project-files.action.delete-container.message=Do you really want to delete this container?
+jsite.project-files.file-options=File Options
+jsite.project-files.default=Default file
+jsite.project-files.default.tooltip=Specify that this file is the project\u2019s index file
+jsite.project-files.insert=Insert
+jsite.project-files.insert.tooltip=Uncheck if this file was inserted externally
+jsite.project-files.custom-key=Custom key
+jsite.project-files.custom-key.tooltip=The externally created key for the file
+jsite.project-files.mime-type=MIME type
+jsite.project-files.mime-type.tooltip=Select the correct MIME type here if the detection failed
+jsite.project-files.container=Container
+jsite.project-files.container.tooltip=Selects a container for the current file
+jsite.project-files.replacement=Replacements
+jsite.project-files.replacement.tooltip=Activates replacements in file
+jsite.project-files.replacement.edition-range=Range
+jsite.project-files.replacement.edition-range.tooltip=Also replace $[EDITION+1], $[EDITION+2]\u2026
+jsite.project-files.scan-error=<html><b>Error scanning files</b><br><br>Either the directory of the project does not exist<br>or some files/directories in it are notaccessible.<br>Please go back and select the correct directory.</html>
+jsite.project-files.empty-index=<html><b>No default file</b><br><br>You did not specify a default file for this project.<br>While it is possible to insert a project without a default<br>file you should specify one to ease browsing.</html>
+jsite.project-files.container-index=<html><b>Default file in container</b><br><br>Your default file was placed in a container!<br>This might make other people shun your page.</html>
+jsite.project-files.index-not-html=<html><b>Default file is not HTML</b><br><br>Your default file does not have the MIME type "text/html"!<br>Loading your Freesite in a browser may give unexpected results.</html>
+jsite.project-files.no-node-running=<html><b>Node is not running</b><br><br>You can not insert a project if your node is not running.<br>Please start your node and try again.</html>
+jsite.project-files.no-custom-key=<html><b>No custom key for file</b><br><br>You specified not to insert <code>{0}</code><br>but failed to enter a key to redirect to!</html>
+jsite.project-files.no-node-selected=<html><b>No node selected</b><br><br>Please select a node from the menu!</html>
--- /dev/null
+#
+# jSite - a tool for uploading websites into Freenet
+# Copyright (C) 2006 David Roden
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# German language file by David Roden <droden@gmail.com>
+
+jsite.main.already-running=<html><b>jSite läuft bereits!</b><br><br>Es wurde festgestellt, dass jSite bereits läuft. Das kann<br>zu Beschädigungen an der Konfiguration führen.</html>
+
+jsite.wizard.previous=Zurück
+jsite.wizard.next=Vorwärts
+jsite.wizard.quit=Beenden
+
+jsite.quit.question=Möchten Sie jSite wirklich beenden?
+jsite.quit.config-not-saved=<html><b>Konfiguration nicht gespeichert</b><br><br>Die Konfiguration konnte nicht gespeichert werden.<br>Soll jSite trotzdem beendet werden?</html>
+
+jsite.menu.languages=Sprachen
+jsite.menu.language.change.restart-message=<html><b>Neustart notwending</b><br><br>Damit die Änderungen an der Sprache wirksam<br>werden, muss jSite neu gestartet werden!</html>
+jsite.menu.language.en=Englisch
+jsite.menu.language.de=Deutsch
+jsite.menu.nodes=Nodes
+jsite.menu.nodes.manage-nodes=Nodes verwalten
+jsite.menu.help=Hilfe
+jsite.menu.help.about=Über
+
+jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006 David Roden<br>Veröffentlicht unter der GNU General Public License</html>
+
+jsite.node-manager.heading=Nodeverwaltung
+jsite.node-manager.description=Verwalten Sie hier Ihre Nodes.
+jsite.node-manager.node-information=Nodeinformation
+jsite.node-manager.add-node=Node hinzufügen
+jsite.node-manager.new-node=Neuer Node
+jsite.node-manager.delete-node=Node löschen
+jsite.node-manager.delete-node.warning=<html><b>Nodelöschung bestätigen</b><br><br>Wollen Sie diesen Node wirklich löschen?</html>
+jsite.node-manager.name=Name
+jsite.node-manager.hostname=Hostname
+jsite.node-manager.port=Port
+
+jsite.insert.heading=Projekt einfügen
+jsite.insert.description=Bitte warten Sie, während das Projekt eingefügt wird.
+jsite.insert.project-information=Projektinformationen
+jsite.insert.request-uri=Freesite
+jsite.insert.start-time=Beginn
+jsite.insert.progress=Fortschritt
+jsite.insert.insert-failed=<html><b>Einfügen fehlgeschlagen</b><br><br>Das Einfügen des Projektes ist fehlgeschlagen, da<br>einige Dateien nicht eingefügt werden konnten.</html>
+jsite.insert.insert-failed-with-cause=<html><b>Einfügen fehlgeschlagen</b><br><br>Das Einfügen des Projektes ist fehlgeschlagen, da<br>einige Dateien nicht eingefügt werden konnten.<br>Folgender Fehler trat auf:<br><br><code>{0}</code></html>
+jsite.insert.inserted=<html><b>Projekt eingefügt</b><br><br>Ihr Projekt wurde erfolgreich eingefügt.</html>
+
+jsite.file-scanner.can-not-read-directory=Kann Verzeichnis nicht lesen
+
+jsite.project.heading=Projekt auswählen
+jsite.project.description=Wählen Sie das Projekt aus, welches sie einfügen möchten, oder erstellen Sie ein neues Projekt.
+jsite.project.action.browse=Durchsuchen
+jsite.project.action.browse.choose=Auswählen
+jsite.project.action.browse.tooltip=Lokalen Pfad für Projekt auswählen
+jsite.project.action.add-project=Projekt erstellen
+jsite.project.action.add-project.tooltip=Ein neues Projekt erstellen
+jsite.project.new-project.name=Neues Projekt
+jsite.project.action.delete-project=Projekt löschen
+jsite.project.action.delete-project.tooltip=Ein Projekt löschen
+jsite.project.action.delete-project.confirm=<html><b>Löschung bestätigen</b><br><br>Das Projekt \u201e{0}\u201c wird gelöscht!<br>Möchten Sie fortfahren?</html>
+jsite.project.action.clone-project=Projekt duplizieren
+jsite.project.action.clone-project.copy=Kopie von {0}
+jsite.project.action.clone-project.tooltip=Das ausgewählte Projekt duplizieren
+jsite.project.project.information=Projektinformation
+jsite.project.project.name=Name
+jsite.project.project.description=Beschreibung
+jsite.project.project.local-path=Lokaler Pfad
+jsite.project.project.address=Adresse
+jsite.project.project.public-key=Anfrage-URI
+jsite.project.project.private-key=Einfüge-URI
+jsite.project.project.path=Pfad
+jsite.project.project.edition=Edition
+jsite.project.keygen.io-error=<html><b>Kommunikation fehlgeschlagen</b><br><br>Die Kommunikation mit dem Freenet Node<br>ergab folgende Fehlermeldung:<br><br><code>{0}</code><br><br>Bitte vergewissern Sie sich, dass der Node läuft und dass Sie<br> den korrekten Hostnamen und die korrekte Portnummer auf der<br>\u201eNode Einstellungen\u201c Seite eingegeben haben.</html>
+jsite.project.warning.no-local-path=<html><b>Kein lokaler Pfad</b><br><br>Sie haben keinen lokalen Pfad für die einzufügenden Dateien angegeben.<br>Es ist nicht möglich, ohne lokalen Pfad weiter zu machen.</html>
+jsite.project.warning.no-path=<html><b>Kein Freesite-Pfad</b><br><br>Sie haben keinen Pfad für die Freesite angegeben.<br>Es ist nicht möglich, ohne einen Freesite-Pfad weiter zu machen.</html>
+
+jsite.project-files.heading=Projektdateien
+jsite.project-files.description=<html>Auf dieser Seite können Parameter für die einzelnen Dateien dieses Projekts angegeben werden, z.B.<br>extern erstellte Schlüssel oder der korrekte MIME-Typ, wenn er nicht automatisch richtig erkannt wurde.</html>
+jsite.project-files.action.rescan=Erneut einlesen
+jsite.project-files.action.rescan.tooltip=Die Liste mit Dateien dieses Projekts neu einlesen
+jsite.project-files.action.add-container=Hinzufügen
+jsite.project-files.action.add-container.tooltip=Erzeugt einen neuen Container und fügt diese Datei hinzu
+jsite.project-files.action.add-container.message=Bitte geben Sie den Namen des neuen Containers an
+jsite.project-files.action.edit-container=Ändern
+jsite.project-files.action.edit-container.tooltip=Ändert den Namen des Containers
+jsite.project-files.action.edit-container.message=Bitte geben Sie den neuen Namen des Containers an
+jsite.project-files.action.delete-container=Löschen
+jsite.project-files.action.delete-container.tooltip=Löscht diesen Container
+jsite.project-files.action.delete-container.message=Wollen Sie diesen Container wirklich löschen?
+jsite.project-files.file-options=Dateioptionen
+jsite.project-files.default=Index-Datei
+jsite.project-files.default.tooltip=Lege Index-Datei für Projekt fest
+jsite.project-files.insert=Einfügen
+jsite.project-files.insert.tooltip=jSite fügt diese Datei ein
+jsite.project-files.custom-key=Extern erstellter Schlüssel
+jsite.project-files.custom-key.tooltip=Der extern erstellte Schlüssel für diese Datei
+jsite.project-files.mime-type=MIME-Typ
+jsite.project-files.mime-type.tooltip=Den richtigen MIME-Typ hier auswählen, wenn die automatische Erkennenung falsch ist
+jsite.project-files.container=Container
+jsite.project-files.container.tooltip=Wählt einen Container für diese Datei aus
+jsite.project-files.replacement=Ersetzungen
+jsite.project-files.replacement.tooltip=Aktiviert Ersetzungen in Datei
+jsite.project-files.replacement.edition-range=Reichweite
+jsite.project-files.replacement.edition-range.tooltip=Ersetzt auch $[EDITION+1], $[EDITION+2], usw.
+jsite.project-files.scan-error=<html><b>Fehler beim Einlesen der Dateien</b><br><br>Entweder existiert das Projektverzeichnis nicht,<br>oder einige Dateien und/oder Verzeichnisse sind nicht lesbar!<br>Bitte gehen Sie zurück und beheben Sie den Fehler!</html>
+jsite.project-files.empty-index=<html><b>Keine Index-Datei gewählt</b><br><br>Sie haben keine Index-Datei für das Projekt angegeben.<br>Obwohl es möglich ist, das zu machen, sollten Sie doch<br>eine Index-Datei angeben, um das Browsen zu erleichtern.</html>
+jsite.project-files.container-index=<html><b>Index-Datei in Container</b><br><br>Ihre Index-Datei befindet sich in einem Container! Das kann<br>dazu führen, dass Ihre Freesite von anderen Leuten gemieden wird.</html>
+jsite.project-files.index-not-html=<html><b>Index-Datei ist kein HTML</b><br><br>Ihre Index-Datei hat nicht den MIME-Typ "text/html"!<br>Das kann beim Besuch Ihrer Freesite zu<br>unerwarteten Ergebnissen führen.</html>
+jsite.project-files.no-node-running=<html><b>Der Node läuft nicht</b><br><br>Sie können das Projekt nicht einfügen, wenn<br>Ihr Node nicht läuft. Bitte starten Sie Ihren Node<br>und probieren Sie es erneut.</html>
+jsite.project-files.no-custom-key=<html><b>Kein externer Schlüssel</b><br><br>Sie haben angegeben, dass die Datei <code>{0}</code><br>nicht eingefügt werden soll. Allerdings haben Sie<br>keinen extern erstellten Schlüssel angegeben.</html>
+jsite.project-files.no-node-selected=<html><b>Kein Node ausgewählt</b><br><br>Bitte wählen Sie einen Node aus dem Menü!</html>
--- /dev/null
+/*
+ * jSite -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.io.PrintWriter;
+
+import de.todesbaum.jsite.application.EditionProject;
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.InsertListener;
+import de.todesbaum.jsite.application.Node;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.application.ProjectInserter;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: CLI.java 418 2006-03-29 17:49:16Z bombe $
+ */
+public class CLI implements InsertListener {
+
+ private Object lockObject = new Object();
+ private PrintWriter outputWriter = new PrintWriter(System.out, true);
+ private Freenet7Interface freenetInterface;
+ private ProjectInserter projectInserter = new ProjectInserter();
+ private Node[] nodes;
+ private Project[] projects;
+ private boolean finished = false;
+ private boolean success;
+
+ private CLI(String[] args) {
+
+ if ((args.length == 0) || args[0].equals("-h") || args[0].equals("--help")) {
+ outputWriter.println("\nParameters:\n");
+ outputWriter.println(" --node=<node name>");
+ outputWriter.println(" --project=<project name>");
+ outputWriter.println(" --local-directory=<local directory>");
+ outputWriter.println(" --path=<path>");
+ outputWriter.println(" --edition=<edition>");
+ outputWriter.println("\nA project gets inserted when a new project is loaded on the command line,");
+ outputWriter.println("or when the command line is finished. --local-directory, --path, and --edition");
+ outputWriter.println("override the parameters in the project.");
+ return;
+ }
+
+ Configuration configuration = new Configuration();
+ if (!configuration.createLockFile()) {
+ outputWriter.println("Lock file found!");
+ return;
+ }
+
+ projectInserter.addInsertListener(this);
+ projects = configuration.getProjects();
+ Node node = configuration.getSelectedNode();
+ nodes = configuration.getNodes();
+
+ freenetInterface = new Freenet7Interface();
+ freenetInterface.setNode(node);
+
+ projectInserter.setFreenetInterface(freenetInterface);
+
+ Project currentProject = null;
+ for (int argumentIndex = 0, argumentSize = args.length; argumentIndex < argumentSize; argumentIndex++) {
+ String argument = args[argumentIndex];
+ String value = argument.substring(argument.indexOf('=') + 1).trim();
+ if (argument.startsWith("--node=")) {
+ Node newNode = getNode(value);
+ if (newNode == null) {
+ outputWriter.println("Node \"" + value + "\" not found.");
+ return;
+ }
+ node = newNode;
+ freenetInterface.setNode(node);
+ } else if (argument.startsWith("--project=")) {
+ if (currentProject != null) {
+ if (insertProject(currentProject)) {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted.");
+ } else {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted.");
+ }
+ currentProject = null;
+ }
+ currentProject = getProject(value);
+ if (currentProject == null) {
+ outputWriter.println("Project \"" + value + "\" not found.");
+ }
+ } else if (argument.startsWith("--local-directory")) {
+ if (currentProject == null) {
+ outputWriter.println("You can't specifiy --local-directory before --project.");
+ return;
+ }
+ currentProject.setLocalPath(value);
+ } else if (argument.startsWith("--path=")) {
+ if (currentProject == null) {
+ outputWriter.println("You can't specify --path before --project.");
+ return;
+ }
+ currentProject.setPath(value);
+ } else if (argument.startsWith("--edition=")) {
+ if (currentProject == null) {
+ outputWriter.println("You can't specify --edition before --project.");
+ return;
+ }
+ if (currentProject instanceof EditionProject) {
+ ((EditionProject) currentProject).setEdition(Integer.parseInt(value));
+ } else {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" is not an edition-based project.");
+ return;
+ }
+ } else {
+ outputWriter.println("Unknown parameter: " + argument);
+ return;
+ }
+ }
+
+ if (currentProject != null) {
+ if (insertProject(currentProject)) {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted.");
+ } else {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted.");
+ }
+ }
+
+ configuration.setProjects(projects);
+ configuration.save();
+ }
+
+ private Project getProject(String name) {
+ for (Project project: projects) {
+ if (project.getName().equals(name)) {
+ return project;
+ }
+ }
+ return null;
+ }
+
+ private Node getNode(String name) {
+ for (Node node: nodes) {
+ if (node.getName().equals(name)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ private boolean insertProject(Project currentProject) {
+ if (!freenetInterface.hasNode()) {
+ outputWriter.println("Node is not running!");
+ return false;
+ }
+ projectInserter.setProject(currentProject);
+ projectInserter.start();
+ synchronized (lockObject) {
+ while (!finished) {
+ try {
+ lockObject.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ return success;
+ }
+
+ //
+ // INTERFACE InsertListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertStarted(Project project) {
+ outputWriter.println("Starting Insert of project \"" + project.getName() + "\".");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized) {
+ outputWriter.println("Progress: " + succeeded + " done, " + failed + " failed, " + fatal + " fatal, " + total + " total" + (finalized ? " (finalized)" : "") + ", " + ((succeeded + failed + fatal) * 100 / total) + "%");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertFinished(Project project, boolean success, Throwable cause) {
+ outputWriter.println("Request URI: " + project.getFinalURI(0));
+ finished = true;
+ if (success) {
+ if (project instanceof EditionProject) {
+ ((EditionProject) project).setEdition(((EditionProject) project).getEdition() + 1);
+ }
+ }
+ this.success = success;
+ synchronized (lockObject) {
+ lockObject.notify();
+ }
+ }
+
+ //
+ // MAIN
+ //
+
+ public static void main(String[] args) {
+ new CLI(args);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import de.todesbaum.jsite.application.EditionProject;
+import de.todesbaum.jsite.application.FileOption;
+import de.todesbaum.jsite.application.Node;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.util.io.StreamCopier;
+import de.todesbaum.util.xml.SimpleXML;
+import de.todesbaum.util.xml.XML;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Configuration.java 418 2006-03-29 17:49:16Z bombe $
+ */
+public class Configuration {
+
+ private String filename;
+ private String lockFilename;
+ private SimpleXML rootNode;
+
+ public Configuration() {
+ filename = System.getProperty("user.home") + "/.jSite/config7";
+ lockFilename = System.getProperty("user.home") + "/.jSite/lock7";
+ readConfiguration();
+ }
+
+ private boolean createConfigDirectory() {
+ File configDirectory = new File(System.getProperty("user.home"), ".jSite");
+ return (configDirectory.exists() && configDirectory.isDirectory()) || configDirectory.mkdirs();
+ }
+
+ public boolean createLockFile() {
+ if (!createConfigDirectory()) {
+ return false;
+ }
+ File lockFile = new File(lockFilename);
+ lockFile.deleteOnExit();
+ try {
+ return lockFile.createNewFile();
+ } catch (IOException e) {
+ }
+ return false;
+ }
+
+ private void readConfiguration() {
+ File configurationFile = new File(filename);
+ if (configurationFile.exists()) {
+ ByteArrayOutputStream fileByteOutputStream = null;
+ FileInputStream fileInputStream = null;
+ try {
+ fileByteOutputStream = new ByteArrayOutputStream();
+ fileInputStream = new FileInputStream(configurationFile);
+ StreamCopier.copy(fileInputStream, fileByteOutputStream, configurationFile.length());
+ fileByteOutputStream.close();
+ byte[] fileBytes = fileByteOutputStream.toByteArray();
+ rootNode = SimpleXML.fromDocument(XML.transformToDocument(fileBytes));
+ return;
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ } finally {
+ if (fileInputStream != null) {
+ try {
+ fileInputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ if (fileByteOutputStream != null) {
+ try {
+ fileByteOutputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+ }
+ rootNode = new SimpleXML("configuration");
+ }
+
+ public boolean save() {
+ File configurationFile = new File(filename);
+ if (!configurationFile.exists()) {
+ File configurationFilePath = configurationFile.getParentFile();
+ if (!configurationFilePath.exists() && !configurationFilePath.mkdirs()) {
+ return false;
+ }
+ }
+ FileOutputStream fileOutputStream = null;
+ ByteArrayInputStream configurationInputStream = null;
+ try {
+ byte[] configurationBytes = XML.transformToByteArray(rootNode.getDocument());
+ configurationInputStream = new ByteArrayInputStream(configurationBytes);
+ fileOutputStream = new FileOutputStream(configurationFile);
+ StreamCopier.copy(configurationInputStream, fileOutputStream, configurationBytes.length);
+ return true;
+ } catch (IOException ioe1) {
+ } finally {
+ if (configurationInputStream != null) {
+ try {
+ configurationInputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ if (fileOutputStream != null) {
+ try {
+ fileOutputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+ return false;
+ }
+
+ private String getNodeValue(String[] nodeNames, String defaultValue) {
+ SimpleXML node = rootNode;
+ int nodeIndex = 0;
+ while ((node != null) && (nodeIndex < nodeNames.length)) {
+ node = node.getNode(nodeNames[nodeIndex++]);
+ }
+ if (node == null) {
+ return defaultValue;
+ }
+ return node.getValue();
+ }
+
+ private int getNodeIntValue(String[] nodeNames, int defaultValue) {
+ try {
+ return Integer.parseInt(getNodeValue(nodeNames, String.valueOf(defaultValue)));
+ } catch (NumberFormatException nfe1) {
+ }
+ return defaultValue;
+ }
+
+ private boolean getNodeBooleanValue(String[] nodeNames, boolean defaultValue) {
+ String nodeValue = getNodeValue(nodeNames, null);
+ if (nodeValue == null) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(nodeValue);
+ }
+
+ public String getNodeAddress() {
+ return getNodeValue(new String[] { "node-address" }, "localhost");
+ }
+
+ public void setNodeAddress(String nodeAddress) {
+ rootNode.replace("node-address", nodeAddress);
+ }
+
+ public int getNodePort() {
+ return getNodeIntValue(new String[] { "node-port" }, 9481);
+ }
+
+ public void setNodePort(int nodePort) {
+ rootNode.replace("node-port", String.valueOf(nodePort));
+ }
+
+ public boolean isSkipNodePage() {
+ return getNodeBooleanValue(new String[] { "skip-node-page" }, false);
+ }
+
+ public void setSkipNodePage(boolean skipNodePage) {
+ rootNode.replace("skip-node-page", String.valueOf(skipNodePage));
+ }
+
+ public Project[] getProjects() {
+ List<Project> projects = new ArrayList<Project>();
+ SimpleXML projectsNode = rootNode.getNode("project-list");
+ if (projectsNode != null) {
+ SimpleXML[] projectNodes = projectsNode.getNodes("project");
+ for (SimpleXML projectNode: projectNodes) {
+ try {
+ Project project = null;
+ SimpleXML typeNode = projectNode.getNode("type");
+ if ("edition".equals(typeNode.getValue())) {
+ EditionProject editionProject = new EditionProject();
+ project = editionProject;
+ editionProject.setEdition(Integer.parseInt(projectNode.getNode("edition").getValue()));
+ }
+ projects.add(project);
+ project.setDescription(projectNode.getNode("description").getValue());
+ project.setIndexFile(projectNode.getNode("index-file").getValue());
+ project.setLastInsertionTime(Long.parseLong(projectNode.getNode("last-insertion-time").getValue()));
+ project.setLocalPath(projectNode.getNode("local-path").getValue());
+ project.setName(projectNode.getNode("name").getValue());
+ project.setPath(projectNode.getNode("path").getValue());
+ project.setInsertURI(projectNode.getNode("insert-uri").getValue());
+ project.setRequestURI(projectNode.getNode("request-uri").getValue());
+ SimpleXML fileOptionsNode = projectNode.getNode("file-options");
+ Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
+ if (fileOptionsNode != null) {
+ SimpleXML[] fileOptionNodes = fileOptionsNode.getNodes("file-option");
+ for (SimpleXML fileOptionNode: fileOptionNodes) {
+ String filename = fileOptionNode.getNode("filename").getValue();
+ FileOption fileOption = project.getFileOption(filename);
+ fileOption.setInsert(Boolean.parseBoolean(fileOptionNode.getNode("insert").getValue()));
+ fileOption.setCustomKey(fileOptionNode.getNode("custom-key").getValue());
+ fileOption.setMimeType(fileOptionNode.getNode("mime-type").getValue());
+ fileOption.setContainer(fileOptionNode.getNode("container").getValue());
+ if (fileOptionNode.getNode("replace-edition") != null) {
+ fileOption.setReplaceEdition(Boolean.parseBoolean(fileOptionNode.getNode("replace-edition").getValue()));
+ fileOption.setEditionRange(Integer.parseInt(fileOptionNode.getNode("edition-range").getValue()));
+ }
+ fileOptions.put(filename, fileOption);
+ }
+ }
+ project.setFileOptions(fileOptions);
+ } catch (NumberFormatException nfe1) {
+ nfe1.printStackTrace();
+ }
+ }
+ }
+ return projects.toArray(new Project[projects.size()]);
+ }
+
+ public void setProjects(Project[] projects) {
+ SimpleXML projectsNode = new SimpleXML("project-list");
+ for (Project project: projects) {
+ SimpleXML projectNode = projectsNode.append("project");
+ if (project instanceof EditionProject) {
+ projectNode.append("type", "edition");
+ projectNode.append("edition", String.valueOf(((EditionProject) project).getEdition()));
+ }
+ projectNode.append("description", project.getDescription());
+ projectNode.append("index-file", project.getIndexFile());
+ projectNode.append("last-insertion-time", String.valueOf(project.getLastInsertionTime()));
+ projectNode.append("local-path", project.getLocalPath());
+ projectNode.append("name", project.getName());
+ projectNode.append("path", project.getPath());
+ projectNode.append("insert-uri", project.getInsertURI());
+ projectNode.append("request-uri", project.getRequestURI());
+ SimpleXML fileOptionsNode = projectNode.append("file-options");
+ Iterator<Entry<String, FileOption>> entries = project.getFileOptions().entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry<String, FileOption> entry = entries.next();
+ FileOption fileOption = entry.getValue();
+ if (fileOption.isCustom()) {
+ SimpleXML fileOptionNode = fileOptionsNode.append("file-option");
+ fileOptionNode.append("filename", entry.getKey());
+ fileOptionNode.append("insert", String.valueOf(fileOption.isInsert()));
+ fileOptionNode.append("custom-key", fileOption.getCustomKey());
+ fileOptionNode.append("mime-type", fileOption.getMimeType());
+ fileOptionNode.append("container", fileOption.getContainer());
+ fileOptionNode.append("replace-edition", String.valueOf(fileOption.getReplaceEdition()));
+ fileOptionNode.append("edition-range", String.valueOf(fileOption.getEditionRange()));
+ }
+ }
+ }
+ rootNode.replace(projectsNode);
+ }
+
+ public Locale getLocale() {
+ String language = getNodeValue(new String[] { "i18n", "language" }, "en");
+ String country = getNodeValue(new String[] { "i18n", "country" }, null);
+ if (country != null) {
+ return new Locale(language, country);
+ }
+ return new Locale(language);
+ }
+
+ public void setLocale(Locale locale) {
+ SimpleXML i18nNode = new SimpleXML("i18n");
+ if (locale.getCountry().length() != 0) {
+ i18nNode.append("country", locale.getCountry());
+ }
+ i18nNode.append("language", locale.getLanguage());
+ rootNode.replace(i18nNode);
+ return;
+ }
+
+ public Node[] getNodes() {
+ SimpleXML nodesNode = rootNode.getNode("nodes");
+ if (nodesNode == null) {
+ String hostname = getNodeAddress();
+ int port = getNodePort();
+ return new Node[] { new Node(hostname, port, "Node") };
+ }
+ SimpleXML[] nodeNodes = nodesNode.getNodes("node");
+ Node[] returnNodes = new Node[nodeNodes.length];
+ int nodeIndex = 0;
+ for (SimpleXML nodeNode: nodeNodes) {
+ String name = nodeNode.getNode("name").getValue();
+ String hostname = nodeNode.getNode("hostname").getValue();
+ int port = Integer.parseInt(nodeNode.getNode("port").getValue());
+ Node node = new Node(hostname, port, name);
+ returnNodes[nodeIndex++] = node;
+ }
+ return returnNodes;
+ }
+
+ public void setNodes(Node[] nodes) {
+ SimpleXML nodesNode = new SimpleXML("nodes");
+ for (Node node: nodes) {
+ SimpleXML nodeNode = nodesNode.append("node");
+ nodeNode.append("name", node.getName());
+ nodeNode.append("hostname", node.getHostname());
+ nodeNode.append("port", String.valueOf(node.getPort()));
+ }
+ rootNode.replace(nodesNode);
+ rootNode.remove("node-address");
+ rootNode.remove("node-port");
+ }
+
+ public void setSelectedNode(Node selectedNode) {
+ SimpleXML selectedNodeNode = new SimpleXML("selected-node");
+ selectedNodeNode.append("name", selectedNode.getName());
+ selectedNodeNode.append("hostname", selectedNode.getHostname());
+ selectedNodeNode.append("port", String.valueOf(selectedNode.getPort()));
+ rootNode.replace(selectedNodeNode);
+ }
+
+ public Node getSelectedNode() {
+ SimpleXML selectedNodeNode = rootNode.getNode("selected-node");
+ if (selectedNodeNode == null) {
+ return null;
+ }
+ String name = selectedNodeNode.getNode("name").getValue();
+ String hostname = selectedNodeNode.getNode("hostname").getValue();
+ int port = Integer.valueOf(selectedNodeNode.getNode("port").getValue());
+ return new Node(hostname, port, name);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonGroup;
+import javax.swing.Icon;
+import javax.swing.JList;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import de.todesbaum.jsite.application.FileOption;
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.Node;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.gui.NodeManagerListener;
+import de.todesbaum.jsite.gui.NodeManagerPage;
+import de.todesbaum.jsite.gui.ProjectFilesPage;
+import de.todesbaum.jsite.gui.ProjectInsertPage;
+import de.todesbaum.jsite.gui.ProjectPage;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.util.image.IconLoader;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+import de.todesbaum.util.swing.WizardListener;
+
+/**
+ * @author <a href="mailto:droden@gmail.com">David Roden </a>
+ * @version $Id: Main.java 456 2006-04-03 17:54:44Z bombe $
+ */
+public class Main implements ActionListener, ListSelectionListener, WizardListener, NodeManagerListener {
+
+ private static boolean debug = false;
+ private Configuration configuration = new Configuration();
+ private Freenet7Interface freenetInterface = new Freenet7Interface();
+ protected Icon jSiteIcon;
+
+ private static enum PageType {
+ PAGE_NODE_MANAGER, PAGE_PROJECTS, PAGE_PROJECT_FILES, PAGE_INSERT_PROJECT
+ }
+
+ private static final Locale[] SUPPORTED_LOCALES = new Locale[] { Locale.ENGLISH, Locale.GERMAN };
+ private Map<Locale, Action> languageActions = new HashMap<Locale, Action>();
+ private Action manageNodeAction;
+ private Action aboutAction;
+ protected TWizard wizard;
+ protected JMenu nodeMenu;
+ private Node selectedNode;
+ private final Map<PageType, TWizardPage> pages = new HashMap<PageType, TWizardPage>();
+
+ private Main() {
+ Locale.setDefault(configuration.getLocale());
+ I18n.setLocale(configuration.getLocale());
+ if (!configuration.createLockFile()) {
+ JOptionPane.showMessageDialog(null, I18n.getMessage("jsite.main.already-running"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ wizard = new TWizard();
+ createActions();
+ wizard.setJMenuBar(createMenuBar());
+ wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ wizard.setPreviousEnabled(false);
+ wizard.setNextEnabled(true);
+ wizard.addWizardListener(this);
+ jSiteIcon = IconLoader.loadIcon("/jsite-icon.png");
+ wizard.setIcon(jSiteIcon);
+
+ initPages();
+ showPage(PageType.PAGE_PROJECTS);
+ wizard.setPreviousName((String) manageNodeAction.getValue(Action.NAME));
+ }
+
+ private void createActions() {
+ for (final Locale locale: SUPPORTED_LOCALES) {
+ languageActions.put(locale, new AbstractAction(I18n.getMessage("jsite.menu.language." + locale.getLanguage())) {
+
+ public void actionPerformed(ActionEvent actionEvent) {
+ switchLanguage(locale);
+ }
+ });
+ }
+ manageNodeAction = new AbstractAction(I18n.getMessage("jsite.menu.nodes.manage-nodes")) {
+ public void actionPerformed(ActionEvent actionEvent) {
+ showPage(PageType.PAGE_NODE_MANAGER);
+ }
+ };
+ aboutAction = new AbstractAction(I18n.getMessage("jsite.menu.help.about")) {
+
+ public void actionPerformed(ActionEvent e) {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.about.message"), Version.getVersion()), null, JOptionPane.INFORMATION_MESSAGE, jSiteIcon);
+ }
+ };
+ }
+
+ private JMenuBar createMenuBar() {
+ JMenuBar menuBar = new JMenuBar();
+ JMenu languageMenu = new JMenu(I18n.getMessage("jsite.menu.languages"));
+ menuBar.add(languageMenu);
+ ButtonGroup languageButtonGroup = new ButtonGroup();
+ for (Locale locale: SUPPORTED_LOCALES) {
+ Action languageAction = languageActions.get(locale);
+ JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(languageActions.get(locale));
+ if (locale.equals(Locale.getDefault())) {
+ menuItem.setSelected(true);
+ }
+ languageAction.putValue("menuItem", menuItem);
+ languageButtonGroup.add(menuItem);
+ languageMenu.add(menuItem);
+ }
+ nodeMenu = new JMenu(I18n.getMessage("jsite.menu.nodes"));
+ menuBar.add(nodeMenu);
+ selectedNode = configuration.getSelectedNode();
+ nodesUpdated(configuration.getNodes());
+
+ /* evil hack to right-align the help menu */
+ JPanel panel = new JPanel();
+ panel.setOpaque(false);
+ menuBar.add(panel);
+
+ JMenu helpMenu = new JMenu(I18n.getMessage("jsite.menu.help"));
+ menuBar.add(helpMenu);
+ helpMenu.add(aboutAction);
+ return menuBar;
+ }
+
+ private void initPages() {
+ NodeManagerPage nodeManagerPage = new NodeManagerPage();
+ nodeManagerPage.setName("page.node-manager");
+ nodeManagerPage.addNodeManagerListener(this);
+ nodeManagerPage.setNodes(configuration.getNodes());
+ pages.put(PageType.PAGE_NODE_MANAGER, nodeManagerPage);
+
+ ProjectPage projectPage = new ProjectPage();
+ projectPage.setName("page.project");
+ projectPage.setProjects(configuration.getProjects());
+ projectPage.setFreenetInterface(freenetInterface);
+ projectPage.addListSelectionListener(this);
+ pages.put(PageType.PAGE_PROJECTS, projectPage);
+
+ ProjectFilesPage projectFilesPage = new ProjectFilesPage();
+ projectFilesPage.setName("page.project.files");
+ pages.put(PageType.PAGE_PROJECT_FILES, projectFilesPage);
+
+ ProjectInsertPage projectInsertPage = new ProjectInsertPage();
+ projectInsertPage.setDebug(debug);
+ projectInsertPage.setName("page.project.insert");
+ projectInsertPage.setFreenetInterface(freenetInterface);
+ pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage);
+ }
+
+ protected void showPage(PageType pageType) {
+ wizard.setPreviousEnabled(pageType.ordinal() > 0);
+ wizard.setNextEnabled(pageType.ordinal() < (pages.size() - 1));
+ wizard.setPage(pages.get(pageType));
+ wizard.setTitle(pages.get(pageType).getHeading() + " - jSite");
+ }
+
+ private boolean saveConfiguration() {
+ NodeManagerPage nodeManagerPage = (NodeManagerPage) pages.get(PageType.PAGE_NODE_MANAGER);
+ configuration.setNodes(nodeManagerPage.getNodes());
+ if (selectedNode != null) {
+ configuration.setSelectedNode(selectedNode);
+ }
+
+ ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
+ configuration.setProjects(projectPage.getProjects());
+
+ return configuration.save();
+ }
+
+ private Locale findSupportedLocale(Locale forLocale) {
+ for (Locale locale: SUPPORTED_LOCALES) {
+ if (locale.equals(forLocale)) {
+ return locale;
+ }
+ }
+ for (Locale locale: SUPPORTED_LOCALES) {
+ if (locale.getCountry().equals(forLocale.getCountry()) && locale.getLanguage().equals(forLocale.getLanguage())) {
+ return locale;
+ }
+ }
+ for (Locale locale: SUPPORTED_LOCALES) {
+ if (locale.getLanguage().equals(forLocale.getLanguage())) {
+ return locale;
+ }
+ }
+ return SUPPORTED_LOCALES[0];
+ }
+
+ //
+ // ACTIONS
+ //
+
+ protected void switchLanguage(Locale locale) {
+ Locale supportedLocale = findSupportedLocale(locale);
+ Action languageAction = languageActions.get(supportedLocale);
+ JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) languageAction.getValue("menuItem");
+ menuItem.setSelected(true);
+ /* show the restart message in the other language! */
+ Locale currentLocale = I18n.getLocale();
+ I18n.setLocale(supportedLocale);
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.menu.language.change.restart-message"), null, JOptionPane.INFORMATION_MESSAGE);
+ I18n.setLocale(currentLocale);
+ configuration.setLocale(supportedLocale);
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void valueChanged(ListSelectionEvent e) {
+ JList list = (JList) e.getSource();
+ int selectedRow = list.getSelectedIndex();
+ wizard.setNextEnabled(selectedRow > -1);
+ }
+
+ //
+ // INTERFACE WizardListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void wizardNextPressed(TWizard wizard) {
+ String pageName = wizard.getPage().getName();
+ if ("page.node-manager".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECTS);
+ wizard.setPreviousName((String) manageNodeAction.getValue(Action.NAME));
+ } else if ("page.project".equals(pageName)) {
+ ProjectPage projectPage = (ProjectPage) wizard.getPage();
+ Project project = projectPage.getSelectedProject();
+ if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-local-path"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project);
+ ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).setProject(project);
+ showPage(PageType.PAGE_PROJECT_FILES);
+ wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ } else if ("page.project.files".equals(pageName)) {
+ ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
+ Project project = projectPage.getSelectedProject();
+ if (selectedNode == null) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (project.getIndexFile() == null) {
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.empty-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ }
+ if (!project.getFileOption(project.getIndexFile()).getContainer().equals("")) {
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.container-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ }
+ if (!project.getFileOption(project.getIndexFile()).getMimeType().equals("text/html")) {
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.index-not-html"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ }
+ Map<String, FileOption> fileOptions = project.getFileOptions();
+ Set<Entry<String, FileOption>> fileOptionEntries = fileOptions.entrySet();
+ for (Entry<String, FileOption> fileOptionEntry: fileOptionEntries) {
+ FileOption fileOption = fileOptionEntry.getValue();
+ if (!fileOption.isInsert() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.project-files.no-custom-key"), fileOptionEntry.getKey()), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ }
+ boolean nodeRunning = false;
+ try {
+ nodeRunning = freenetInterface.isNodePresent();
+ } catch (IOException e) {
+ }
+ if (!nodeRunning) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ showPage(PageType.PAGE_INSERT_PROJECT);
+ nodeMenu.setEnabled(false);
+ } else if ("page.project.insert".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECTS);
+ nodeMenu.setEnabled(true);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void wizardPreviousPressed(TWizard wizard) {
+ String pageName = wizard.getPage().getName();
+ if ("page.project".equals(pageName)) {
+ showPage(PageType.PAGE_NODE_MANAGER);
+ wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ } else if ("page.project.files".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECTS);
+ wizard.setPreviousName((String) manageNodeAction.getValue(Action.NAME));
+ } else if ("page.project.insert".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECT_FILES);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void wizardQuitPressed(TWizard wizard) {
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
+ if (saveConfiguration()) {
+ System.exit(0);
+ }
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.config-not-saved"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
+ System.exit(0);
+ }
+ }
+ }
+
+ //
+ // INTERFACE NodeManagerListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void nodesUpdated(Node[] nodes) {
+ nodeMenu.removeAll();
+ ButtonGroup nodeButtonGroup = new ButtonGroup();
+ Node newSelectedNode = null;
+ for (Node node: nodes) {
+ JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName());
+ nodeMenuItem.putClientProperty("Node", node);
+ nodeMenuItem.addActionListener(this);
+ nodeButtonGroup.add(nodeMenuItem);
+ if (node.equals(selectedNode)) {
+ newSelectedNode = node;
+ nodeMenuItem.setSelected(true);
+ }
+ nodeMenu.add(nodeMenuItem);
+ }
+ nodeMenu.addSeparator();
+ nodeMenu.add(manageNodeAction);
+ selectedNode = newSelectedNode;
+ freenetInterface.setNode(selectedNode);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void actionPerformed(ActionEvent e) {
+ Object source = e.getSource();
+ if (source instanceof JRadioButtonMenuItem) {
+ JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source;
+ Node node = (Node) menuItem.getClientProperty("Node");
+ selectedNode = node;
+ freenetInterface.setNode(selectedNode);
+ }
+ }
+
+ //
+ // MAIN METHOD
+ //
+
+ public static void main(String[] args) {
+ System.setProperty("swing.plaf.metal.userFont", "Tahoma");
+ System.setProperty("swing.plaf.metal.controlFont", "Tahoma");
+ System.setProperty("swing.aatext", "true");
+ debug = (args.length > 0) && (args[0].equals("--debug"));
+ new Main();
+ }
+
+}
--- /dev/null
+/*
+ * jSite - a tool for uploading websites into Freenet
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+/**
+ * @author <a href="mailto:droden@gmail.com">David Roden </a>
+ * @version $Id: Version.java 457 2006-04-03 22:08:35Z bombe $
+ */
+public class Version {
+
+ private static final String VERSION = "0.4";
+
+ public static final String getVersion() {
+ return VERSION;
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Client executes {@link Command}s over a {@link Connection} to a
+ * {@link Node} and delivers resulting {@link Message}s.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Client.java 413 2006-03-29 12:22:31Z bombe $
+ */
+public class Client implements ConnectionListener {
+
+ /** The connection this client operates on. */
+ private final Connection connection;
+
+ /** The identifiers the client filters messages for. */
+ private List<String> identifiers = new ArrayList<String>();
+
+ /** The queued messages. */
+ private final List<Message> messageQueue = new ArrayList<Message>();
+
+ /** Whether the client was disconnected. */
+ private boolean disconnected = false;
+
+ /** Whether to catch all messages from the connection. */
+ private boolean catchAll = false;
+
+ /**
+ * Creates a new client that operates on the specified connection.
+ *
+ * @param connection
+ * The connection to operate on
+ */
+ public Client(Connection connection) {
+ this.connection = connection;
+ connection.addConnectionListener(this);
+ }
+
+ /**
+ * Creates a new client that operates on the specified connection and
+ * immediately executes the specified command.
+ *
+ * @param connection
+ * The connection to operate on
+ * @param command
+ * The command to execute
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #execute(Command)
+ */
+ public Client(Connection connection, Command command) throws IOException {
+ this(connection);
+ execute(command);
+ }
+
+ /**
+ * Returns whether this client catches all messages going over the
+ * connection.
+ *
+ * @return <code>true</code> if the client catches all messages,
+ * <code>false</code> otherwise
+ */
+ public boolean isCatchAll() {
+ return catchAll;
+ }
+
+ /**
+ * Sets whether this client catches all messages going over the connection.
+ *
+ * @param catchAll
+ * <code>true</code> if the client should catch all messages,
+ * <code>false</code> otherwise
+ */
+ public void setCatchAll(boolean catchAll) {
+ this.catchAll = catchAll;
+ }
+
+ /**
+ * Executes the specified command. This will also clear the queue of
+ * messages, discarding all messages that resulted from the previous command
+ * and have not yet been read.
+ *
+ * @param command
+ * The command to execute
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #execute(Command, boolean)
+ */
+ public void execute(Command command) throws IOException {
+ execute(command, true);
+ }
+
+ /**
+ * Executes the specified command and optionally clears the list of
+ * identifiers this clients listens to before starting the command.
+ *
+ * @param command
+ * The command to execute
+ * @param removeExistingIdentifiers
+ * If <code>true</code>, the list of identifiers that this
+ * clients listens to is cleared
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public void execute(Command command, boolean removeExistingIdentifiers) throws IOException {
+ synchronized (messageQueue) {
+ messageQueue.clear();
+ if (removeExistingIdentifiers) {
+ identifiers.clear();
+ }
+ identifiers.add(command.getIdentifier());
+ }
+ connection.execute(command);
+ }
+
+ /**
+ * Returns the next message, waiting endlessly for it, if need be. If you
+ * are not sure whether a message will arrive, better use
+ * {@link #readMessage(long)} to only wait for a specific time.
+ *
+ * @return The next message that resulted from the execution of the last
+ * command
+ * @see #readMessage(long)
+ * @see #execute(Command)
+ */
+ public Message readMessage() {
+ return readMessage(0);
+ }
+
+ /**
+ * Returns the next message. If the message queue is currently empty, at
+ * least <code>maxWaitTime</code> milliseconds will be waited for a
+ * message to arrive.
+ *
+ * @param maxWaitTime
+ * The minimum time to wait for a message, in milliseconds
+ * @return The message, or <code>null</code> if no message arrived in time
+ * or the client is currently disconnected
+ * @see #isDisconnected()
+ * @see Object#wait(long)
+ */
+ public Message readMessage(long maxWaitTime) {
+ synchronized (messageQueue) {
+ if (disconnected) {
+ return null;
+ }
+ if (messageQueue.size() == 0) {
+ try {
+ messageQueue.wait(maxWaitTime);
+ } catch (InterruptedException ie1) {
+ }
+ }
+ if (messageQueue.size() > 0) {
+ return messageQueue.remove(0);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the client is currently disconnected.
+ *
+ * @return <code>true</code> if the client is disconnected,
+ * <code>false</code> otherwise
+ */
+ public boolean isDisconnected() {
+ synchronized (messageQueue) {
+ return disconnected;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void messageReceived(Connection connection, Message message) {
+ synchronized (messageQueue) {
+ if (catchAll || (message.getIdentifier().length() == 0) || identifiers.contains(message.getIdentifier())) {
+ messageQueue.add(message);
+ messageQueue.notify();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionTerminated(Connection connection) {
+ synchronized (messageQueue) {
+ disconnected = true;
+ messageQueue.notify();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Implementation of the <code>ClientHello</code> command. This command must
+ * be sent as the first command on a connection ({@link de.todesbaum.util.freenet.fcp2.Connection#connect()}
+ * takes care of that) and must not be sent afterwards.
+ * <p>
+ * The node can answer with the following messages: <code>NodeHello</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ClientHello.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public class ClientHello extends Command {
+
+ /** The name of the client. */
+ protected String name;
+
+ /** The version of the FCP protocol the client expects. */
+ protected String expectedVersion = "2.0";
+
+ /**
+ * Creates a new <code>ClientHello</code> command.
+ */
+ public ClientHello() {
+ super("ClientHello", "ClientHello-" + System.currentTimeMillis());
+ }
+
+ /**
+ * Returns the value of the <code>ExpectedVersion</code> parameter of this
+ * command. At the moment this value is not used by the node but in the
+ * future this may be used to enforce certain node versions.
+ *
+ * @return The expected version
+ */
+ public String getExpectedVersion() {
+ return expectedVersion;
+ }
+
+ /**
+ * Sets the value of the <code>ExpectedVersion</code> parameter of this
+ * command. At the moment this value is not used by the node but in the
+ * future this may be used to enforce certain node versions.
+ *
+ * @param expectedVersion
+ * The expected version
+ */
+ public void setExpectedVersion(String expectedVersion) {
+ this.expectedVersion = expectedVersion;
+ }
+
+ /**
+ * Returns the name of the client that is connecting.
+ *
+ * @return The name of the client
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the client that is connecting.
+ *
+ * @param name
+ * The name of the client
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ writer.write("Name=" + name + LINEFEED);
+ writer.write("ExpectedVersion=" + expectedVersion + LINEFEED);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all put requests. It contains all parameters that put
+ * requests have in common.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ClientPut.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public abstract class ClientPut extends Command {
+
+ /** The URI of this request. */
+ protected final String uri;
+
+ /** The client token of this request. */
+ protected String clientToken = null;
+
+ /** Whether this request should only create a CHK. */
+ protected boolean getCHKOnly = false;
+
+ /** Whether this request is a global request. */
+ protected boolean global = false;
+
+ /** Whether the node should not try to compress the file. */
+ protected boolean dontCompress = false;
+
+ /** The maximum number of retries of this command. */
+ protected int maxRetries = 0;
+
+ /** The persistence of this request. */
+ protected Persistence persistence = Persistence.CONNECTION;
+
+ /** The priority class of this request. */
+ protected PriorityClass priorityClass = PriorityClass.INTERACTIVE;
+
+ /** The verbosiry of this request. */
+ protected Verbosity verbosity = Verbosity.NONE;
+
+ /**
+ * Creates a new put request with the specified name, identifier and URI.
+ *
+ * @param name
+ * The name of this request
+ * @param identifier
+ * The identifier of this request
+ * @param uri
+ * The URI of this request
+ */
+ protected ClientPut(String name, String identifier, String uri) {
+ super(name, identifier);
+ this.uri = uri;
+ }
+
+ /**
+ * Returns whether the node should not try to compress the data.
+ *
+ * @return <code>true</code> if the node should <strong>not</strong> try
+ * to compress the data
+ */
+ public boolean isDontCompress() {
+ return dontCompress;
+ }
+
+ /**
+ * Sets whether the node should not try to compress the data. A client might
+ * set this hint on data that is clearly not compressible, like MPEG audio
+ * files, JPEG or PNG images, highly compressed movies, or compressed
+ * archives like ZIP files. Otherwise the node will try to compress the file
+ * which -- depending on the size of the data -- might take a lot of time
+ * and memory.
+ *
+ * @param dontCompress
+ * <code>true</code> if the node should <strong>not</strong>
+ * try to compress the data
+ */
+ public void setDontCompress(boolean dontCompress) {
+ this.dontCompress = dontCompress;
+ }
+
+ /**
+ * Returns whether this request should only return the CHK of the data.
+ * @return Whether this request should only return the CHK of the data
+ */
+ public boolean isGetCHKOnly() {
+ return getCHKOnly;
+ }
+
+ /**
+ * Sets whether this request should only return the CHK of the data.
+ * @param getCHKOnly
+ * <code>true</code> if this request should only return the CHK of the data
+ */
+ public void setGetCHKOnly(boolean getCHKOnly) {
+ this.getCHKOnly = getCHKOnly;
+ }
+
+ /**
+ * Returns whether this request is a global request.
+ * @return <code>true</code> if this request is a global request, <code>false</code> otherwise
+ */
+ public boolean isGlobal() {
+ return global;
+ }
+
+ /**
+ * Sets whether this request is a global request.
+ * @param global
+ * <code>true</code> if this request is a global request, <code>false</code> otherwise
+ */
+ public void setGlobal(boolean global) {
+ this.global = global;
+ }
+
+ /**
+ * Returns the maximum number of retries of this request.
+ * @return The maximum number of retries of this request
+ */
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ /**
+ * Sets the maximum number of retries of this request
+ * @param maxRetries
+ * The maximum number of retries of this request
+ */
+ public void setMaxRetries(int maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ /**
+ * Returns the priority class of this request.
+ * @return The priority class of this request
+ */
+ public PriorityClass getPriorityClass() {
+ return priorityClass;
+ }
+
+ /**
+ * Sets the priority class of this request.
+ * @param priorityClass
+ * The priority class of this request
+ */
+ public void setPriorityClass(PriorityClass priorityClass) {
+ this.priorityClass = priorityClass;
+ }
+
+ /**
+ * Returns the verbosity of this request.
+ * @return The verbosity of this request
+ */
+ public Verbosity getVerbosity() {
+ return verbosity;
+ }
+
+ /**
+ * Sets the verbosity of this request.
+ * @param verbosity
+ * The verbosity of this request
+ */
+ public void setVerbosity(Verbosity verbosity) {
+ this.verbosity = verbosity;
+ }
+
+ /**
+ * Returns the URI of this request
+ * @return The URI of this request.
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ writer.write("URI=" + uri + LINEFEED);
+ if (verbosity != null)
+ writer.write("Verbosity=" + verbosity.getValue() + LINEFEED);
+ if (maxRetries != 0)
+ writer.write("MaxRetries=" + maxRetries + LINEFEED);
+ if (priorityClass != null)
+ writer.write("PriorityClass=" + priorityClass.getValue() + LINEFEED);
+ writer.write("GetCHKOnly=" + getCHKOnly + LINEFEED);
+ writer.write("Global=" + global + LINEFEED);
+ writer.write("DontCompress=" + dontCompress + LINEFEED);
+ if (clientToken != null)
+ writer.write("ClientToken=" + clientToken + LINEFEED);
+ if (persistence != null)
+ writer.write("Persistence=" + persistence.getName() + LINEFEED);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.SequenceInputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * Implementation of the <code>ClientPutComplexDir</code> command. This
+ * command can be used to insert directories that do not exist on disk.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ClientPutComplexDir.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public class ClientPutComplexDir extends ClientPutDir {
+
+ /** The file entries of this directory. */
+ private List<FileEntry> fileEntries = new ArrayList<FileEntry>();
+
+ /** Whether this request has payload. */
+ private boolean hasPayload = false;
+
+ /** The input streams for the payload. */
+ private List<InputStream> payloadInputStreams = new ArrayList<InputStream>();
+
+ /** The total number of bytes of the payload. */
+ private long payloadLength = 0;
+
+ /**
+ * Creates a new <code>ClientPutComplexDir</code> command with the specified identifier and URI.
+ * @param identifier The identifier of the command
+ * @param uri The URI of the command
+ */
+ public ClientPutComplexDir(String identifier, String uri) {
+ super("ClientPutComplexDir", identifier, uri);
+ }
+
+ /**
+ * Adds a file to the directory inserted by this request.
+ * @param fileEntry The file entry to add to the directory
+ */
+ public void addFileEntry(FileEntry fileEntry) {
+ fileEntries.add(fileEntry);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ int fileIndex = 0;
+ for (FileEntry fileEntry: fileEntries) {
+ writer.write("Files." + fileIndex + ".Name=" + fileEntry.getFilename() + LINEFEED);
+ if (fileEntry.getContentType() != null) {
+ writer.write("Files." + fileIndex + ".Metadata.ContentType=" + fileEntry.getContentType() + LINEFEED);
+ }
+ writer.write("Files." + fileIndex + ".UploadFrom=" + fileEntry.getName() + LINEFEED);
+ if (fileEntry instanceof DirectFileEntry) {
+ hasPayload = true;
+ writer.write("Files." + fileIndex + ".DataLength=" + ((DirectFileEntry) fileEntry).getDataLength() + LINEFEED);
+ payloadLength += ((DirectFileEntry) fileEntry).getDataLength();
+ payloadInputStreams.add(((DirectFileEntry) fileEntry).getDataInputStream());
+ } else if (fileEntry instanceof DiskFileEntry) {
+ writer.write("Files." + fileIndex + ".Filename=" + ((DiskFileEntry) fileEntry).getFilename() + LINEFEED);
+ } else if (fileEntry instanceof RedirectFileEntry) {
+ writer.write("Files." + fileIndex + ".TargetURI=" + ((RedirectFileEntry) fileEntry).getTargetURI() + LINEFEED);
+ }
+ fileIndex++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean hasPayload() {
+ return hasPayload;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected long getPayloadLength() {
+ return payloadLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected InputStream getPayload() {
+ /* grr. use Vector here because it returns an Enumeration. */
+ Vector<InputStream> inputStreams = new Vector<InputStream>(payloadInputStreams);
+ return new SequenceInputStream(inputStreams.elements());
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all put requests that insert a directory.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ClientPutDir.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public class ClientPutDir extends ClientPut {
+
+ /** The default file of the directory. */
+ protected String defaultName;
+
+ /**
+ * Creates a new request with the specified name, identifier, and URI.
+ *
+ * @param name
+ * The name of the request
+ * @param identifier
+ * The identifier of the request
+ * @param uri
+ * The URI of the request
+ */
+ public ClientPutDir(String name, String identifier, String uri) {
+ super(name, identifier, uri);
+ }
+
+ /**
+ * Returns the default name of the directory.
+ *
+ * @return The default name of the directory
+ */
+ public String getDefaultName() {
+ return defaultName;
+ }
+
+ /**
+ * Sets the default name of the directory. The default name of a directory
+ * is the name of the file that will be delivered if the directory was
+ * requested without a filename. It's about the same as the
+ * <code>index.html</code> file that gets delivered if you only request a
+ * directory from a webserver.
+ *
+ * @param defaultName
+ * The default name of the directory
+ */
+ public void setDefaultName(String defaultName) {
+ this.defaultName = defaultName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ if (defaultName != null)
+ writer.write("DefaultName=" + defaultName + LINEFEED);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all commands.
+ * <p>
+ * In addition to the replies listed at the type comment of each specific
+ * command the node can <strong>always</strong> send the following messages:
+ * <code>ProtocolError</code> (if this library screws up),
+ * <code>CloseConnectionDuplicateClientName</code> (if a client with the same
+ * name of the {@link de.todesbaum.util.freenet.fcp2.Connection} connects). So
+ * when receiving messages from the node you should always be prepared for
+ * something you did not expect.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Command.java 371 2006-03-25 10:38:13Z bombe $
+ */
+public abstract class Command {
+
+ /** The line feed sequence used by the library. */
+ protected static final String LINEFEED = "\r\n";
+
+ /**
+ * The name of the command. The name is sent to the node so it can not be
+ * chosen arbitrarily!
+ */
+ private final String commandName;
+
+ /**
+ * The identifier of the command. This identifier is used to identify
+ * replies that are caused by a command.
+ */
+ private final String identifier;
+
+ /**
+ * Creates a new command with the specified name and identifier.
+ *
+ * @param name
+ * The name of the command
+ * @param identifier
+ * The identifier of the command
+ */
+ public Command(String name, String identifier) {
+ this.commandName = name;
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the name of this command.
+ *
+ * @return The name of this command
+ */
+ public String getCommandName() {
+ return commandName;
+ }
+
+ /**
+ * Return the identifier of this command.
+ *
+ * @return The identifier of this command
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Writes all parameters to the specified writer.
+ * <p>
+ * <strong>NOTE:</strong> Subclasses of Command <strong>must</strong> call
+ * <code>super.write(writer)</code> before or after writing their own
+ * parameters!
+ *
+ * @param writer
+ * The stream to write the parameters to
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ protected void write(Writer writer) throws IOException {
+ if (identifier != null)
+ writer.write("Identifier=" + identifier + LINEFEED);
+ }
+
+ /**
+ * Returns whether this command has payload to send after the message.
+ * Subclasses need to return <code>true</code> here if they need to send
+ * payload after the message.
+ *
+ * @return <code>true</code> if this command has payload to send,
+ * <code>false</code> otherwise
+ */
+ protected boolean hasPayload() {
+ return false;
+ }
+
+ /**
+ * Returns the payload of this command as an {@link InputStream}. This
+ * method is never called if {@link #hasPayload()} returns
+ * <code>false</code>.
+ *
+ * @return The payload of this command
+ */
+ protected InputStream getPayload() {
+ return null;
+ }
+
+ /**
+ * Returns the length of the payload. This method is never called if
+ * {@link #hasPayload()} returns <code>false</code>.
+ *
+ * @return The length of the payload
+ */
+ protected long getPayloadLength() {
+ return -1;
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.Socket;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.todesbaum.util.io.LineInputStream;
+import de.todesbaum.util.io.StreamCopier;
+import de.todesbaum.util.io.TempFileInputStream;
+
+/**
+ * A physical connection to a Freenet node.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Connection.java 413 2006-03-29 12:22:31Z bombe $
+ */
+public class Connection {
+
+ /** The listeners that receive events from this connection. */
+ private List<ConnectionListener> connectionListeners = new ArrayList<ConnectionListener>();
+
+ /** The node this connection is connected to. */
+ private final Node node;
+
+ /** The name of this connection. */
+ private final String name;
+
+ /** The network socket of this connection. */
+ private Socket nodeSocket;
+
+ /** The input stream that reads from the socket. */
+ private InputStream nodeInputStream;
+
+ /** The output stream that writes to the socket. */
+ private OutputStream nodeOutputStream;
+
+ /** The thread that reads from the socket. */
+ private NodeReader nodeReader;
+
+ /** A writer for the output stream. */
+ private Writer nodeWriter;
+
+ /** The NodeHello message sent by the node on connect. */
+ protected Message nodeHello;
+
+ /**
+ * Creates a new connection to the specified node with the specified name.
+ *
+ * @param node
+ * The node to connect to
+ * @param name
+ * The name of this connection
+ */
+ public Connection(Node node, String name) {
+ this.node = node;
+ this.name = name;
+ }
+
+ /**
+ * Adds a listener that gets notified on connection events.
+ *
+ * @param connectionListener
+ * The listener to add
+ */
+ public void addConnectionListener(ConnectionListener connectionListener) {
+ connectionListeners.add(connectionListener);
+ }
+
+ /**
+ * Removes a listener from the list of registered listeners. Only the first
+ * matching listener is removed.
+ *
+ * @param connectionListener
+ * The listener to remove
+ * @see List#remove(java.lang.Object)
+ */
+ public void removeConnectionListener(ConnectionListener connectionListener) {
+ connectionListeners.remove(connectionListener);
+ }
+
+ /**
+ * Notifies listeners about a received message.
+ *
+ * @param message
+ * The received message
+ */
+ protected void fireMessageReceived(Message message) {
+ for (ConnectionListener connectionListener: connectionListeners) {
+ connectionListener.messageReceived(this, message);
+ }
+ }
+
+ /**
+ * Notifies listeners about the loss of the connection.
+ */
+ protected void fireConnectionTerminated() {
+ for (ConnectionListener connectionListener: connectionListeners) {
+ connectionListener.connectionTerminated(this);
+ }
+ }
+
+ /**
+ * Returns the name of the connection.
+ *
+ * @return The name of the connection
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Connects to the node.
+ *
+ * @return <code>true</code> if the connection succeeded and the node
+ * returned a NodeHello message
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #getNodeHello()
+ */
+ public synchronized boolean connect() throws IOException {
+ nodeSocket = null;
+ nodeInputStream = null;
+ nodeOutputStream = null;
+ nodeWriter = null;
+ nodeReader = null;
+ try {
+ nodeSocket = new Socket(node.getHostname(), node.getPort());
+ nodeSocket.setReceiveBufferSize(65535);
+ nodeInputStream = nodeSocket.getInputStream();
+ nodeOutputStream = nodeSocket.getOutputStream();
+ // nodeWriter = new TeeWriter(new
+ // OutputStreamWriter(nodeOutputStream, Charset.forName("UTF-8")),
+ // new PrintWriter(System.out));
+ nodeWriter = new OutputStreamWriter(nodeOutputStream, Charset.forName("UTF-8"));
+ nodeReader = new NodeReader(nodeInputStream);
+ Thread nodeReaderThread = new Thread(nodeReader);
+ nodeReaderThread.setDaemon(true);
+ nodeReaderThread.start();
+ ClientHello clientHello = new ClientHello();
+ clientHello.setName(name);
+ clientHello.setExpectedVersion("2.0");
+ execute(clientHello);
+ synchronized (this) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ return nodeHello != null;
+ } catch (IOException ioe1) {
+ disconnect();
+ throw ioe1;
+ }
+ }
+
+ /**
+ * Returns whether this connection is still connected to the node.
+ *
+ * @return <code>true</code> if this connection is still valid,
+ * <code>false</code> otherwise
+ */
+ public boolean isConnected() {
+ return (nodeHello != null) && (nodeSocket != null) && (nodeSocket.isConnected());
+ }
+
+ /**
+ * Returns the NodeHello message the node sent on connection.
+ *
+ * @return The NodeHello message of the node
+ */
+ public Message getNodeHello() {
+ return nodeHello;
+ }
+
+ /**
+ * Disconnects from the node.
+ */
+ public void disconnect() {
+ if (nodeWriter != null) {
+ try {
+ nodeWriter.close();
+ } catch (IOException ioe1) {
+ }
+ nodeWriter = null;
+ }
+ if (nodeOutputStream != null) {
+ try {
+ nodeOutputStream.close();
+ } catch (IOException ioe1) {
+ }
+ nodeOutputStream = null;
+ }
+ if (nodeInputStream != null) {
+ try {
+ nodeInputStream.close();
+ } catch (IOException ioe1) {
+ }
+ nodeInputStream = null;
+ }
+ if (nodeSocket != null) {
+ try {
+ nodeSocket.close();
+ } catch (IOException ioe1) {
+ }
+ nodeSocket = null;
+ }
+ fireConnectionTerminated();
+ }
+
+ /**
+ * Executes the specified command.
+ *
+ * @param command
+ * The command to execute
+ * @throws IllegalStateException
+ * if the connection is not connected
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public synchronized void execute(Command command) throws IllegalStateException, IOException {
+ if (nodeSocket == null) {
+ throw new IllegalStateException("connection is not connected");
+ }
+ nodeWriter.write(command.getCommandName() + Command.LINEFEED);
+ command.write(nodeWriter);
+ nodeWriter.write("EndMessage" + Command.LINEFEED);
+ nodeWriter.flush();
+ if (command.hasPayload()) {
+ StreamCopier.copy(command.getPayload(), nodeOutputStream, command.getPayloadLength());
+ nodeOutputStream.flush();
+ }
+ }
+
+ /**
+ * The reader thread for this connection. This is essentially a thread that
+ * reads lines from the node, creates messages from them and notifies
+ * listeners about the messages.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Connection.java 413 2006-03-29 12:22:31Z bombe $
+ */
+ private class NodeReader implements Runnable {
+
+ /** The input stream to read from. */
+ @SuppressWarnings("hiding")
+ private InputStream nodeInputStream;
+
+ /**
+ * Creates a new reader that reads from the specified input stream.
+ *
+ * @param nodeInputStream
+ * The input stream to read from
+ */
+ public NodeReader(InputStream nodeInputStream) {
+ this.nodeInputStream = nodeInputStream;
+ }
+
+ /**
+ * Main loop of the reader. Lines are read and converted into
+ * {@link Message} objects.
+ */
+ public void run() {
+ LineInputStream nodeReader = null;
+ try {
+ nodeReader = new LineInputStream(nodeInputStream);
+ String line = "";
+ Message message = null;
+ while (line != null) {
+ line = nodeReader.readLine();
+ // System.err.println("> " + line);
+ if (line == null) {
+ break;
+ }
+ if (message == null) {
+ message = new Message(line);
+ continue;
+ }
+ if ("Data".equals(line)) {
+ /* need to read message from stream now */
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile("fcpv2", "data");
+ tempFile.deleteOnExit();
+ FileOutputStream tempFileOutputStream = new FileOutputStream(tempFile);
+ long dataLength = Long.parseLong(message.get("DataLength"));
+ StreamCopier.copy(nodeInputStream, tempFileOutputStream, dataLength);
+ tempFileOutputStream.close();
+ message.setPayloadInputStream(new TempFileInputStream(tempFile));
+ } catch (IOException ioe1) {
+ ioe1.printStackTrace();
+ }
+ }
+ if ("Data".equals(line) || "EndMessage".equals(line)) {
+ if (message.getName().equals("NodeHello")) {
+ nodeHello = message;
+ synchronized (Connection.this) {
+ Connection.this.notify();
+ }
+ } else {
+ fireMessageReceived(message);
+ }
+ message = null;
+ continue;
+ }
+ int equalsPosition = line.indexOf('=');
+ if (equalsPosition > -1) {
+ String key = line.substring(0, equalsPosition).trim();
+ String value = line.substring(equalsPosition + 1).trim();
+ if (key.equals("Identifier")) {
+ message.setIdentifier(value);
+ } else {
+ message.put(key, value);
+ }
+ continue;
+ }
+ /* skip lines consisting of whitespace only */
+ if (line.trim().length() == 0) {
+ continue;
+ }
+ /* if we got here, some error occured! */
+ throw new IOException("Unexpected line: " + line);
+ }
+ } catch (IOException ioe1) {
+ // ioe1.printStackTrace();
+ } finally {
+ if (nodeReader != null) {
+ try {
+ nodeReader.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ if (nodeInputStream != null) {
+ try {
+ nodeInputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+ Connection.this.disconnect();
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.util.EventListener;
+
+/**
+ * Interface for clients that want to be notified when a message was received.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ConnectionListener.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public interface ConnectionListener extends EventListener {
+
+ /**
+ * Notifies a client that a message was received.
+ *
+ * @param connection
+ * The connection the message was received on
+ * @param message
+ * The message that was received
+ */
+ public void messageReceived(Connection connection, Message message);
+
+ /**
+ * Notifies a client that the connection to the node has been lost.
+ *
+ * @param connection
+ * The connection that was lost
+ */
+ public void connectionTerminated(Connection connection);
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * A {@link FileEntry} that sends its payload directly to the node, using the
+ * existing FCP connection.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: DirectFileEntry.java 413 2006-03-29 12:22:31Z bombe $
+ */
+public class DirectFileEntry extends FileEntry {
+
+ /** The input stream to read the data for this file from. */
+ private final InputStream dataInputStream;
+
+ /** The length of the data. */
+ private final long dataLength;
+
+ /**
+ * Creates a new FileEntry with the specified name and content type that
+ * gets its data from the specified byte array.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file
+ * @param dataBytes
+ * The content of the file
+ */
+ public DirectFileEntry(String filename, String contentType, byte[] dataBytes) {
+ this(filename, contentType, new ByteArrayInputStream(dataBytes), dataBytes.length);
+ }
+
+ /**
+ * Creates a new FileEntry with the specified name and content type that
+ * gets its data from the specified input stream.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file
+ * @param dataInputStream
+ * The input stream to read the content from
+ * @param dataLength
+ * The length of the data input stream
+ */
+ public DirectFileEntry(String filename, String contentType, InputStream dataInputStream, long dataLength) {
+ super(filename, contentType);
+ this.dataInputStream = dataInputStream;
+ this.dataLength = dataLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return "direct";
+ }
+
+ /**
+ * Returns the input stream for the file's content.
+ *
+ * @return The input stream for the file's content
+ */
+ public InputStream getDataInputStream() {
+ return dataInputStream;
+ }
+
+ /**
+ * Returns the length of this file's content.
+ *
+ * @return The length of this file's content
+ */
+ public long getDataLength() {
+ return dataLength;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * A {@link FileEntry} that reads the content from a file on the disk.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: DiskFileEntry.java 413 2006-03-29 12:22:31Z bombe $
+ */
+public class DiskFileEntry extends FileEntry {
+
+ /** The local file name. */
+ private final String localFilename;
+
+ /**
+ * Creates a new {@link FileEntry} with the specified name and content type
+ * that is read from the file specified by <code>localFilename</code>.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file
+ * @param localFilename
+ * The name of the local file that holds the content of the file
+ * to insert
+ */
+ public DiskFileEntry(String filename, String contentType, String localFilename) {
+ super(filename, contentType);
+ this.localFilename = localFilename;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return "disk";
+ }
+
+ /**
+ * Returns the name of the local file that holds the content for this file.
+ *
+ * @return The name of the local file
+ */
+ public String getLocalFilename() {
+ return localFilename;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Abstract base class of file entries that are used in the
+ * {@link de.todesbaum.util.freenet.fcp2.ClientPutComplexDir} command to define
+ * the files of an insert.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: FileEntry.java 413 2006-03-29 12:22:31Z bombe $
+ */
+public abstract class FileEntry {
+
+ /** The name of the file. */
+ private final String filename;
+
+ /** The content type of the file. */
+ private final String contentType;
+
+ /**
+ * Creates a new file entry with the specified name and content type. The
+ * content type should be a standard MIME type with an additional charset
+ * specification for text-based types.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file, e.g.
+ * <code>"application/x-tar"</code> or
+ * <code>"text/html; charset=iso8859-15"</code>
+ */
+ protected FileEntry(String filename, String contentType) {
+ this.filename = filename;
+ this.contentType = contentType;
+ }
+
+ /**
+ * Returns the name of this entry's type. Can be one of <code>direct</code>,
+ * <code>disk</code>, or <code>redirect</code>. This method is
+ * implemented by the subclasses {@link DirectFileEntry},
+ * {@link DiskFileEntry}, and {@link RedirectFileEntry}, respectively.
+ *
+ * @return The name of this entry's type
+ */
+ public abstract String getName();
+
+ /**
+ * Returns the content type of this file.
+ *
+ * @return The content type of this file
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ /**
+ * Returns the name of this file.
+ *
+ * @return The name of this file
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Implementation of the <code>GenerateSSK</code> command.
+ * <p>
+ * The node can answer with the following messages: <code>SSKKeypair</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: GenerateSSK.java 413 2006-03-29 12:22:31Z bombe $
+ */
+public class GenerateSSK extends Command {
+
+ /**
+ * Creates a new <code>GenerateSSK</code> request.
+ */
+ public GenerateSSK() {
+ super("GenerateSSK", null);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * Contains replies sent by the Freenet node. A message always has a name, and
+ * most of the messages also have an identifier which binds it to a specific
+ * command. Exceptions are among others <code>NodeHello</code>,
+ * <code>SSKKeypair</code>, and <code>EndListPersistentRequests</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Message.java 413 2006-03-29 12:22:31Z bombe $
+ * @see de.todesbaum.util.freenet.fcp2.Client
+ */
+public class Message {
+
+ /** The name of this message. */
+ private final String name;
+
+ /** The identifier of this message. */
+ private String identifier = "";
+
+ /** The parameters of this message. */
+ private Map<String, String> parameters = new HashMap<String, String>();
+
+ /** The payload. */
+ private InputStream payloadInputStream;
+
+ /**
+ * Creates a new message with the specified name.
+ *
+ * @param name
+ * The name of this message
+ */
+ public Message(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the identifier of this message.
+ *
+ * @return The identifier
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Sets the identifier of this message.
+ *
+ * @param identifier
+ * The identifier of this message
+ */
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the name of this message.
+ *
+ * @return The name of this message
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Tests whether this message contains the parameter with the specified key.
+ * Key names are compared ignoring case.
+ *
+ * @param key
+ * The name of the parameter
+ * @return <code>true</code> if this parameter exists in this message,
+ * <code>false</code> otherwise
+ */
+ public boolean containsKey(String key) {
+ return parameters.containsKey(key.toLowerCase());
+ }
+
+ /**
+ * Returns all parameters of this message. The keys of the entries are all
+ * lower case so if you want to match the parameter names you have to watch
+ * out.
+ *
+ * @return All parameters of this message
+ */
+ public Set<Entry<String, String>> entrySet() {
+ return parameters.entrySet();
+ }
+
+ /**
+ * Returns the value of the parameter with the name specified by
+ * <code>key</code>.
+ *
+ * @param key
+ * The name of the parameter
+ * @return The value of the parameter
+ */
+ public String get(String key) {
+ return parameters.get(key.toLowerCase());
+ }
+
+ /**
+ * Stores the specified value as parameter with the name specified by
+ * <code>key</code>.
+ *
+ * @param key
+ * The name of the parameter
+ * @param value
+ * The value of the parameter
+ * @return The previous value, or <code>null</code> if there was no
+ * previous value
+ */
+ public String put(String key, String value) {
+ return parameters.put(key.toLowerCase(), value);
+ }
+
+ /**
+ * Returns the number of parameters in this message.
+ *
+ * @return The number of parameters
+ */
+ public int size() {
+ return parameters.size();
+ }
+
+ /**
+ * @return Returns the payloadInputStream.
+ */
+ public InputStream getPayloadInputStream() {
+ return payloadInputStream;
+ }
+
+ /**
+ * @param payloadInputStream
+ * The payloadInputStream to set.
+ */
+ public void setPayloadInputStream(InputStream payloadInputStream) {
+ this.payloadInputStream = payloadInputStream;
+ }
+
+ /**
+ * Returns a textual representation of this message, containing its name,
+ * the identifier, and the parameters.
+ *
+ * @return A textual representation of this message
+ */
+ public String toString() {
+ return name + "[identifier=" + identifier + ",parameters=" + parameters.toString() + "]";
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Contains the hostname and port number of the Freenet node.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Node.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public class Node {
+
+ /** The default port of FCPv2. */
+ public static final int DEFAULT_PORT = 9481;
+
+ /** The hostname of the node. */
+ protected String hostname;
+
+ /** The port number of the node. */
+ protected int port;
+
+ /**
+ * Creates a new node with the specified hostname and the default port
+ * number.
+ *
+ * @param hostname
+ * The hostname of the node
+ * @see #DEFAULT_PORT
+ */
+ public Node(String hostname) {
+ this(hostname, DEFAULT_PORT);
+ }
+
+ /**
+ * Creates a new node with the specified hostname and port number.
+ *
+ * @param hostname
+ * The hostname of the node
+ * @param port
+ * The port number of the node
+ */
+ public Node(String hostname, int port) {
+ this.hostname = hostname;
+ this.port = port;
+ }
+
+ /**
+ * Returns the hostname of the node.
+ *
+ * @return The hostname of the node
+ */
+ public String getHostname() {
+ return hostname;
+ }
+
+ /**
+ * Returns the port number of the node.
+ *
+ * @return The port number of the node
+ */
+ public int getPort() {
+ return port;
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Persistence.java 373 2006-03-25 10:42:52Z bombe $
+ */
+public final class Persistence {
+
+ public static final Persistence CONNECTION = new Persistence("connection");
+ public static final Persistence REBOOT = new Persistence("reboot");
+ public static final Persistence FOREVER = new Persistence("forever");
+
+ private String name;
+
+ private Persistence(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return Returns the name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: PriorityClass.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public final class PriorityClass {
+
+ public static final PriorityClass MAXIMUM = new PriorityClass("maximum", 0);
+ public static final PriorityClass INTERACTIVE = new PriorityClass("interactive", 1);
+ public static final PriorityClass SEMI_INTERACTIVE = new PriorityClass("semiInteractive", 2);
+ public static final PriorityClass UPDATABLE = new PriorityClass("updatable", 3);
+ public static final PriorityClass BULK = new PriorityClass("bulk", 4);
+ public static final PriorityClass PREFETCH = new PriorityClass("prefetch", 5);
+ public static final PriorityClass MINIMUM = new PriorityClass("minimum", 6);
+
+ private String name;
+ private int value;
+
+ private PriorityClass(String name, int value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * @return Returns the name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return Returns the value.
+ */
+ public int getValue() {
+ return value;
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+public class RedirectFileEntry extends FileEntry {
+
+ final String targetURI;
+
+ public RedirectFileEntry(String filename, String contentType, String targetURI) {
+ super(filename, contentType);
+ this.targetURI = targetURI;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return "redirect";
+ }
+
+ /**
+ * @return Returns the targetURI.
+ */
+ public String getTargetURI() {
+ return targetURI;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: Verbosity.java 356 2006-03-24 15:13:38Z bombe $
+ */
+public final class Verbosity {
+
+ public static final Verbosity PROGRESS = new Verbosity(1);
+ public static final Verbosity COMPRESSION = new Verbosity(512);
+
+ public static final Verbosity NONE = new Verbosity(0);
+ public static final Verbosity ALL = new Verbosity(PROGRESS, COMPRESSION);
+
+ private final int value;
+
+ private Verbosity(int value) {
+ this.value = value;
+ }
+
+ private Verbosity(Verbosity verbosity1, Verbosity verbosity2) {
+ this(verbosity1.value | verbosity2.value);
+ }
+
+ /**
+ * @return Returns the value.
+ */
+ public int getValue() {
+ return value;
+ }
+
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * 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 for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.image;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+/**
+ * @author <a href="mailto:droden@gmail.com">David Roden</a>
+ * @version $Id: IconLoader.java 130 2006-02-18 18:27:11Z bombe $
+ */
+public class IconLoader {
+
+ public static Icon loadIcon(String resourceName) {
+ try {
+ InputStream resourceStream = IconLoader.class.getResourceAsStream(resourceName);
+ if (resourceStream == null) {
+ return null;
+ }
+ ByteArrayOutputStream imageOutput = new ByteArrayOutputStream();
+ byte[] buffer = new byte[16384];
+ int r = 0;
+ while ((r = resourceStream.read(buffer)) != -1) {
+ imageOutput.write(buffer, 0, r);
+ }
+ imageOutput.flush();
+ return new ImageIcon(imageOutput.toByteArray());
+ } catch (IOException e) {
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: LineInputStream.java 429 2006-03-29 18:04:48Z bombe $
+ */
+public class LineInputStream extends FilterInputStream {
+
+ private boolean skipLinefeed = false;
+ private StringBuffer lineBuffer = new StringBuffer();
+
+ /**
+ * @param in
+ */
+ public LineInputStream(InputStream in) {
+ super(in);
+ }
+
+ public synchronized String readLine() throws IOException {
+ lineBuffer.setLength(0);
+ int c = 0;
+ while (c != -1) {
+ c = read();
+ if ((c == -1) && lineBuffer.length() == 0)
+ return null;
+ if (skipLinefeed && (c == '\n')) {
+ skipLinefeed = false;
+ continue;
+ }
+ skipLinefeed = (c == '\r');
+ if ((c == '\r') || (c == '\n')) {
+ c = -1;
+ } else {
+ lineBuffer.append((char) c);
+ }
+ }
+ return lineBuffer.toString();
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: ReplacingOutputStream.java 431 2006-03-29 18:06:18Z bombe $
+ */
+public class ReplacingOutputStream extends FilterOutputStream {
+
+ private Map<String, String> replacements = new HashMap<String, String>();
+ private StringBuffer ringBuffer = new StringBuffer();
+
+ /**
+ * @param out
+ */
+ public ReplacingOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public void addReplacement(String token, String value) {
+ replacements.put(token, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(int b) throws IOException {
+ ringBuffer.append((char) b);
+ Iterator<Entry<String, String>> entries = replacements.entrySet().iterator();
+ boolean found = false;
+ Entry<String, String> entry = null;
+ while (!found && entries.hasNext()) {
+ entry = entries.next();
+ if (entry.getKey().startsWith(ringBuffer.toString())) {
+ found = true;
+ }
+ }
+ if (!found) {
+ String buffer = ringBuffer.toString();
+ for (int index = 0, size = buffer.length(); index < size; index++) {
+ super.write(buffer.charAt(index));
+ }
+ ringBuffer.setLength(0);
+ } else {
+ if (entry.getKey().equals(ringBuffer.toString())) {
+ String buffer = entry.getValue();
+ for (int index = 0, size = buffer.length(); index < size; index++) {
+ super.write(buffer.charAt(index));
+ }
+ ringBuffer.setLength(0);
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * 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 for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Copies input from an {@link InputStream} to an {@link OutputStream}.
+ *
+ * @author <a href="mailto:droden@gmail.com">David Roden</a>
+ * @version $Id: StreamCopier.java 428 2006-03-29 18:03:36Z bombe $
+ */
+public class StreamCopier {
+
+ /**
+ * The default size of the buffer.
+ */
+ private static final int BUFFER_SIZE = 64 * 1024;
+
+ /**
+ * The {@link InputStream} to read from.
+ */
+ private InputStream inputStream;
+
+ /**
+ * The {@link OutputStream} to write to.
+ */
+ private OutputStream outputStream;
+
+ /**
+ * The number of bytes to copy.
+ */
+ private long length;
+
+ /**
+ * The size of the buffer.
+ */
+ private int bufferSize;
+
+ /**
+ * Creates a new StreamCopier with the specified parameters and the default
+ * buffer size.
+ *
+ * @param inputStream
+ * The {@link InputStream} to read from
+ * @param outputStream
+ * The {@link OutputStream} to write to
+ * @param length
+ * The number of bytes to copy
+ */
+ public StreamCopier(InputStream inputStream, OutputStream outputStream, long length) {
+ this(inputStream, outputStream, length, BUFFER_SIZE);
+ }
+
+ /**
+ * Creates a new StreamCopier with the specified parameters and the default
+ * buffer size.
+ *
+ * @param inputStream
+ * The {@link InputStream} to read from
+ * @param outputStream
+ * The {@link OutputStream} to write to
+ * @param length
+ * The number of bytes to copy
+ * @param bufferSize
+ * The number of bytes to copy at a time
+ */
+ public StreamCopier(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) {
+ this.inputStream = inputStream;
+ this.outputStream = outputStream;
+ this.length = length;
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * Copies the stream data. If the input stream is depleted before the
+ * requested number of bytes have been read an {@link EOFException} is
+ * thrown.
+ *
+ * @throws EOFException
+ * if the input stream is depleted before the requested number
+ * of bytes has been read
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public void copy() throws EOFException, IOException {
+ copy(inputStream, outputStream, length, bufferSize);
+ }
+
+ /**
+ * Copies <code>length</code> bytes from the <code>inputStream</code> to
+ * the <code>outputStream</code>.
+ *
+ * @param inputStream
+ * The input stream to read from
+ * @param outputStream
+ * The output stream to write to
+ * @param length
+ * The number of bytes to copy
+ * @throws IOException
+ * if an I/O exception occurs
+ */
+ public static void copy(InputStream inputStream, OutputStream outputStream, long length) throws IOException {
+ copy(inputStream, outputStream, length, BUFFER_SIZE);
+ }
+
+ /**
+ * Copies <code>length</code> bytes from the <code>inputStream</code> to
+ * the <code>outputStream</code> using a buffer with the specified size
+ *
+ * @param inputStream
+ * The input stream to read from
+ * @param outputStream
+ * The output stream to write to
+ * @param length
+ * The number of bytes to copy
+ * @param bufferSize
+ * The size of the copy buffer
+ * @throws IOException
+ * if an I/O exception occurs
+ */
+ public static void copy(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) throws IOException {
+ long remaining = length;
+ byte[] buffer = new byte[bufferSize];
+ while (remaining > 0) {
+ int read = inputStream.read(buffer, 0, (int) Math.min(Integer.MAX_VALUE, Math.min(bufferSize, remaining)));
+ if (read == -1) {
+ throw new EOFException();
+ }
+ outputStream.write(buffer, 0, read);
+ remaining -= read;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class TempFileInputStream extends FileInputStream {
+
+ private File tempFile;
+
+ /**
+ * @param name
+ * @throws FileNotFoundException
+ */
+ public TempFileInputStream(String name) throws FileNotFoundException {
+ this(new File(name));
+ }
+
+ /**
+ * @param file
+ * @throws FileNotFoundException
+ */
+ public TempFileInputStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+
+ public void close() throws IOException {
+ super.close();
+ tempFile.delete();
+ }
+
+}
--- /dev/null
+/* taken from freenet (http://www.freenetproject.org/) */
+package de.todesbaum.util.mime;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * Holds the default MIME types.
+ */
+public class DefaultMIMETypes {
+
+ /** Default MIME type - what to set it to if we don't know any better */
+ public static final String DEFAULT_MIME_TYPE = "application/octet-stream";
+
+ /** MIME types: number -> name */
+ private static List<String> mimeTypesByNumber = new Vector<String>();
+
+ /** MIME types: name -> number */
+ private static Map<String, Short> mimeTypesByName = new HashMap<String, Short>();
+
+ /** MIME types by extension. One extension maps to one MIME type, but not necessarily
+ * the other way around. */
+ private static Map<String, Short> mimeTypesByExtension = new HashMap<String, Short>();
+
+ /** Primary extension by MIME type number. */
+ private static Map<Short, String> primaryExtensionByMimeNumber = new HashMap<Short, String>();
+
+ /**
+ * Add a MIME type, without any extensions.
+ * @param number The number of the MIME type for compression. This *must not change*
+ * for a given type, or the metadata format will be affected.
+ * @param type The actual MIME type string. Do not include ;charset= etc; these are
+ * parameters and there is a separate mechanism for them.
+ */
+ protected static synchronized void addMIMEType(short number, String type) {
+ if(mimeTypesByNumber.size() > number) {
+ String s = mimeTypesByNumber.get(number);
+ if(s != null) throw new IllegalArgumentException("Already used: "+number);
+ } else {
+ mimeTypesByNumber.add(number, null);
+ }
+ mimeTypesByNumber.set(number, type);
+ mimeTypesByName.put(type, new Short(number));
+ }
+
+ /**
+ * Add a MIME type.
+ * @param number The number of the MIME type for compression. This *must not change*
+ * for a given type, or the metadata format will be affected.
+ * @param type The actual MIME type string. Do not include ;charset= etc; these are
+ * parameters and there is a separate mechanism for them.
+ * @param extensions An array of common extensions for files of this type. Must be
+ * unique for the type.
+ */
+ protected static synchronized void addMIMEType(short number, String type, String[] extensions, String outExtension) {
+ addMIMEType(number, type);
+ Short t = new Short(number);
+ if(extensions != null) {
+ for(int i=0;i<extensions.length;i++) {
+ String ext = extensions[i].toLowerCase();
+ if(mimeTypesByExtension.containsKey(ext)) {
+ // No big deal
+ //Short s = mimeTypesByExtension.get(ext);
+ } else {
+ // If only one, make it primary
+ if(outExtension == null && extensions.length == 1)
+ primaryExtensionByMimeNumber.put(t, ext);
+ mimeTypesByExtension.put(ext, t);
+ }
+ }
+ }
+ if(outExtension != null)
+ primaryExtensionByMimeNumber.put(t, outExtension);
+
+ }
+
+ /**
+ * Add a MIME type, with extensions separated by spaces. This is more or less
+ * the format in /etc/mime-types.
+ */
+ protected static synchronized void addMIMEType(short number, String type, String extensions) {
+ addMIMEType(number, type, extensions.split(" "), null);
+ }
+
+ /**
+ * Add a MIME type, with extensions separated by spaces. This is more or less
+ * the format in /etc/mime-types.
+ */
+ protected static synchronized void addMIMEType(short number, String type, String extensions, String outExtension) {
+ addMIMEType(number, type, extensions.split(" "), outExtension);
+ }
+
+ /**
+ * Get a known MIME type by number.
+ */
+ public static String byNumber(short x) {
+ if(x > mimeTypesByNumber.size() || x < 0)
+ return null;
+ return mimeTypesByNumber.get(x);
+ }
+
+ /**
+ * Get the number of a MIME type, or -1 if it is not in the table of known MIME
+ * types, in which case it will have to be sent uncompressed.
+ */
+ public static short byName(String s) {
+ Short x = mimeTypesByName.get(s);
+ if(x != null) return x.shortValue();
+ return -1;
+ }
+
+ /* From toad's /etc/mime.types
+ * cat /etc/mime.types | sed "/^$/d;/#/d" | tr --squeeze '\t' ' ' |
+ * (y=0; while read x; do echo "$x" |
+ * sed -n "s/^\([^ ]*\)$/addMIMEType\($y, \"\1\"\);/p;s/^\([^ (),]\+\) \(.*\)$/addMIMEType\($y, \"\1\", \"\2\"\);/p;"; y=$((y+1)); done)
+ */
+
+ static {
+ addMIMEType((short) 0, "application/activemessage");
+ addMIMEType((short) 1, "application/andrew-inset", "ez");
+ addMIMEType((short) 2, "application/applefile");
+ addMIMEType((short) 3, "application/atomicmail");
+ addMIMEType((short) 4, "application/batch-SMTP");
+ addMIMEType((short) 5, "application/beep+xml");
+ addMIMEType((short) 6, "application/cals-1840");
+ addMIMEType((short) 7, "application/commonground");
+ addMIMEType((short) 8, "application/cu-seeme", "cu");
+ addMIMEType((short) 9, "application/cybercash");
+ addMIMEType((short) 10, "application/dca-rft");
+ addMIMEType((short) 11, "application/dec-dx");
+ addMIMEType((short) 12, "application/docbook+xml");
+ addMIMEType((short) 13, "application/dsptype", "tsp");
+ addMIMEType((short) 14, "application/dvcs");
+ addMIMEType((short) 15, "application/edi-consent");
+ addMIMEType((short) 16, "application/edi-x12");
+ addMIMEType((short) 17, "application/edifact");
+ addMIMEType((short) 18, "application/eshop");
+ addMIMEType((short) 19, "application/font-tdpfr");
+ addMIMEType((short) 20, "application/futuresplash", "spl");
+ addMIMEType((short) 21, "application/ghostview");
+ addMIMEType((short) 22, "application/hta", "hta");
+ addMIMEType((short) 23, "application/http");
+ addMIMEType((short) 24, "application/hyperstudio");
+ addMIMEType((short) 25, "application/iges");
+ addMIMEType((short) 26, "application/index");
+ addMIMEType((short) 27, "application/index.cmd");
+ addMIMEType((short) 28, "application/index.obj");
+ addMIMEType((short) 29, "application/index.response");
+ addMIMEType((short) 30, "application/index.vnd");
+ addMIMEType((short) 31, "application/iotp");
+ addMIMEType((short) 32, "application/ipp");
+ addMIMEType((short) 33, "application/isup");
+ addMIMEType((short) 34, "application/java-archive", "jar");
+ addMIMEType((short) 35, "application/java-serialized-object", "ser");
+ addMIMEType((short) 36, "application/java-vm", "class");
+ addMIMEType((short) 37, "application/mac-binhex40", "hqx");
+ addMIMEType((short) 38, "application/mac-compactpro", "cpt");
+ addMIMEType((short) 39, "application/macwriteii");
+ addMIMEType((short) 40, "application/marc");
+ addMIMEType((short) 41, "application/mathematica", "nb");
+ addMIMEType((short) 42, "application/mathematica-old");
+ addMIMEType((short) 43, "application/msaccess", "mdb");
+ addMIMEType((short) 44, "application/msword", "doc dot");
+ addMIMEType((short) 45, "application/news-message-id");
+ addMIMEType((short) 46, "application/news-transmission");
+ addMIMEType((short) 47, "application/ocsp-request");
+ addMIMEType((short) 48, "application/ocsp-response");
+ addMIMEType((short) 49, "application/octet-stream", "bin");
+ addMIMEType((short) 50, "application/oda", "oda");
+ addMIMEType((short) 51, "application/ogg", "ogg");
+ addMIMEType((short) 52, "application/parityfec");
+ addMIMEType((short) 53, "application/pdf", "pdf");
+ addMIMEType((short) 54, "application/pgp-encrypted");
+ addMIMEType((short) 55, "application/pgp-keys", "key");
+ addMIMEType((short) 56, "application/pgp-signature", "pgp");
+ addMIMEType((short) 57, "application/pics-rules", "prf");
+ addMIMEType((short) 58, "application/pkcs10");
+ addMIMEType((short) 59, "application/pkcs7-mime");
+ addMIMEType((short) 60, "application/pkcs7-signature");
+ addMIMEType((short) 61, "application/pkix-cert");
+ addMIMEType((short) 62, "application/pkix-crl");
+ addMIMEType((short) 63, "application/pkixcmp");
+ addMIMEType((short) 64, "application/postscript", "ps ai eps");
+ addMIMEType((short) 65, "application/prs.alvestrand.titrax-sheet");
+ addMIMEType((short) 66, "application/prs.cww");
+ addMIMEType((short) 67, "application/prs.nprend");
+ addMIMEType((short) 68, "application/qsig");
+ addMIMEType((short) 69, "application/rar", "rar");
+ addMIMEType((short) 70, "application/rdf+xml", "rdf");
+ addMIMEType((short) 71, "application/remote-printing");
+ addMIMEType((short) 72, "application/riscos");
+ addMIMEType((short) 73, "application/rss+xml", "rss");
+ addMIMEType((short) 74, "application/rtf");
+ addMIMEType((short) 75, "application/sdp");
+ addMIMEType((short) 76, "application/set-payment");
+ addMIMEType((short) 77, "application/set-payment-initiation");
+ addMIMEType((short) 78, "application/set-registration");
+ addMIMEType((short) 79, "application/set-registration-initiation");
+ addMIMEType((short) 80, "application/sgml");
+ addMIMEType((short) 81, "application/sgml-open-catalog");
+ addMIMEType((short) 82, "application/sieve");
+ addMIMEType((short) 83, "application/slate");
+ addMIMEType((short) 84, "application/smil", "smi smil");
+ addMIMEType((short) 85, "application/timestamp-query");
+ addMIMEType((short) 86, "application/timestamp-reply");
+ addMIMEType((short) 87, "application/vemmi");
+ addMIMEType((short) 88, "application/whoispp-query");
+ addMIMEType((short) 89, "application/whoispp-response");
+ addMIMEType((short) 90, "application/wita");
+ addMIMEType((short) 91, "application/wordperfect", "wpd");
+ addMIMEType((short) 92, "application/wordperfect5.1", "wp5");
+ addMIMEType((short) 93, "application/x400-bp");
+ addMIMEType((short) 94, "application/xhtml+xml", "xhtml xht");
+ addMIMEType((short) 95, "application/xml", "xml xsl");
+ addMIMEType((short) 96, "application/xml-dtd");
+ addMIMEType((short) 97, "application/xml-external-parsed-entity");
+ addMIMEType((short) 98, "application/zip", "zip");
+ addMIMEType((short) 99, "application/vnd.3M.Post-it-Notes");
+ addMIMEType((short) 100, "application/vnd.accpac.simply.aso");
+ addMIMEType((short) 101, "application/vnd.accpac.simply.imp");
+ addMIMEType((short) 102, "application/vnd.acucobol");
+ addMIMEType((short) 103, "application/vnd.aether.imp");
+ addMIMEType((short) 104, "application/vnd.anser-web-certificate-issue-initiation");
+ addMIMEType((short) 105, "application/vnd.anser-web-funds-transfer-initiation");
+ addMIMEType((short) 106, "application/vnd.audiograph");
+ addMIMEType((short) 107, "application/vnd.bmi");
+ addMIMEType((short) 108, "application/vnd.businessobjects");
+ addMIMEType((short) 109, "application/vnd.canon-cpdl");
+ addMIMEType((short) 110, "application/vnd.canon-lips");
+ addMIMEType((short) 111, "application/vnd.cinderella", "cdy");
+ addMIMEType((short) 112, "application/vnd.claymore");
+ addMIMEType((short) 113, "application/vnd.commerce-battelle");
+ addMIMEType((short) 114, "application/vnd.commonspace");
+ addMIMEType((short) 115, "application/vnd.comsocaller");
+ addMIMEType((short) 116, "application/vnd.contact.cmsg");
+ addMIMEType((short) 117, "application/vnd.cosmocaller");
+ addMIMEType((short) 118, "application/vnd.ctc-posml");
+ addMIMEType((short) 119, "application/vnd.cups-postscript");
+ addMIMEType((short) 120, "application/vnd.cups-raster");
+ addMIMEType((short) 121, "application/vnd.cups-raw");
+ addMIMEType((short) 122, "application/vnd.cybank");
+ addMIMEType((short) 123, "application/vnd.dna");
+ addMIMEType((short) 124, "application/vnd.dpgraph");
+ addMIMEType((short) 125, "application/vnd.dxr");
+ addMIMEType((short) 126, "application/vnd.ecdis-update");
+ addMIMEType((short) 127, "application/vnd.ecowin.chart");
+ addMIMEType((short) 128, "application/vnd.ecowin.filerequest");
+ addMIMEType((short) 129, "application/vnd.ecowin.fileupdate");
+ addMIMEType((short) 130, "application/vnd.ecowin.series");
+ addMIMEType((short) 131, "application/vnd.ecowin.seriesrequest");
+ addMIMEType((short) 132, "application/vnd.ecowin.seriesupdate");
+ addMIMEType((short) 133, "application/vnd.enliven");
+ addMIMEType((short) 134, "application/vnd.epson.esf");
+ addMIMEType((short) 135, "application/vnd.epson.msf");
+ addMIMEType((short) 136, "application/vnd.epson.quickanime");
+ addMIMEType((short) 137, "application/vnd.epson.salt");
+ addMIMEType((short) 138, "application/vnd.epson.ssf");
+ addMIMEType((short) 139, "application/vnd.ericsson.quickcall");
+ addMIMEType((short) 140, "application/vnd.eudora.data");
+ addMIMEType((short) 141, "application/vnd.fdf");
+ addMIMEType((short) 142, "application/vnd.ffsns");
+ addMIMEType((short) 143, "application/vnd.flographit");
+ addMIMEType((short) 144, "application/vnd.framemaker");
+ addMIMEType((short) 145, "application/vnd.fsc.weblaunch");
+ addMIMEType((short) 146, "application/vnd.fujitsu.oasys");
+ addMIMEType((short) 147, "application/vnd.fujitsu.oasys2");
+ addMIMEType((short) 148, "application/vnd.fujitsu.oasys3");
+ addMIMEType((short) 149, "application/vnd.fujitsu.oasysgp");
+ addMIMEType((short) 150, "application/vnd.fujitsu.oasysprs");
+ addMIMEType((short) 151, "application/vnd.fujixerox.ddd");
+ addMIMEType((short) 152, "application/vnd.fujixerox.docuworks");
+ addMIMEType((short) 153, "application/vnd.fujixerox.docuworks.binder");
+ addMIMEType((short) 154, "application/vnd.fut-misnet");
+ addMIMEType((short) 155, "application/vnd.grafeq");
+ addMIMEType((short) 156, "application/vnd.groove-account");
+ addMIMEType((short) 157, "application/vnd.groove-identity-message");
+ addMIMEType((short) 158, "application/vnd.groove-injector");
+ addMIMEType((short) 159, "application/vnd.groove-tool-message");
+ addMIMEType((short) 160, "application/vnd.groove-tool-template");
+ addMIMEType((short) 161, "application/vnd.groove-vcard");
+ addMIMEType((short) 162, "application/vnd.hhe.lesson-player");
+ addMIMEType((short) 163, "application/vnd.hp-HPGL");
+ addMIMEType((short) 164, "application/vnd.hp-PCL");
+ addMIMEType((short) 165, "application/vnd.hp-PCLXL");
+ addMIMEType((short) 166, "application/vnd.hp-hpid");
+ addMIMEType((short) 167, "application/vnd.hp-hps");
+ addMIMEType((short) 168, "application/vnd.httphone");
+ addMIMEType((short) 169, "application/vnd.hzn-3d-crossword");
+ addMIMEType((short) 170, "application/vnd.ibm.MiniPay");
+ addMIMEType((short) 171, "application/vnd.ibm.afplinedata");
+ addMIMEType((short) 172, "application/vnd.ibm.modcap");
+ addMIMEType((short) 173, "application/vnd.informix-visionary");
+ addMIMEType((short) 174, "application/vnd.intercon.formnet");
+ addMIMEType((short) 175, "application/vnd.intertrust.digibox");
+ addMIMEType((short) 176, "application/vnd.intertrust.nncp");
+ addMIMEType((short) 177, "application/vnd.intu.qbo");
+ addMIMEType((short) 178, "application/vnd.intu.qfx");
+ addMIMEType((short) 179, "application/vnd.irepository.package+xml");
+ addMIMEType((short) 180, "application/vnd.is-xpr");
+ addMIMEType((short) 181, "application/vnd.japannet-directory-service");
+ addMIMEType((short) 182, "application/vnd.japannet-jpnstore-wakeup");
+ addMIMEType((short) 183, "application/vnd.japannet-payment-wakeup");
+ addMIMEType((short) 184, "application/vnd.japannet-registration");
+ addMIMEType((short) 185, "application/vnd.japannet-registration-wakeup");
+ addMIMEType((short) 186, "application/vnd.japannet-setstore-wakeup");
+ addMIMEType((short) 187, "application/vnd.japannet-verification");
+ addMIMEType((short) 188, "application/vnd.japannet-verification-wakeup");
+ addMIMEType((short) 189, "application/vnd.koan");
+ addMIMEType((short) 190, "application/vnd.lotus-1-2-3");
+ addMIMEType((short) 191, "application/vnd.lotus-approach");
+ addMIMEType((short) 192, "application/vnd.lotus-freelance");
+ addMIMEType((short) 193, "application/vnd.lotus-notes");
+ addMIMEType((short) 194, "application/vnd.lotus-organizer");
+ addMIMEType((short) 195, "application/vnd.lotus-screencam");
+ addMIMEType((short) 196, "application/vnd.lotus-wordpro");
+ addMIMEType((short) 197, "application/vnd.mcd");
+ addMIMEType((short) 198, "application/vnd.mediastation.cdkey");
+ addMIMEType((short) 199, "application/vnd.meridian-slingshot");
+ addMIMEType((short) 200, "application/vnd.mif");
+ addMIMEType((short) 201, "application/vnd.minisoft-hp3000-save");
+ addMIMEType((short) 202, "application/vnd.mitsubishi.misty-guard.trustweb");
+ addMIMEType((short) 203, "application/vnd.mobius.daf");
+ addMIMEType((short) 204, "application/vnd.mobius.dis");
+ addMIMEType((short) 205, "application/vnd.mobius.msl");
+ addMIMEType((short) 206, "application/vnd.mobius.plc");
+ addMIMEType((short) 207, "application/vnd.mobius.txf");
+ addMIMEType((short) 208, "application/vnd.motorola.flexsuite");
+ addMIMEType((short) 209, "application/vnd.motorola.flexsuite.adsi");
+ addMIMEType((short) 210, "application/vnd.motorola.flexsuite.fis");
+ addMIMEType((short) 211, "application/vnd.motorola.flexsuite.gotap");
+ addMIMEType((short) 212, "application/vnd.motorola.flexsuite.kmr");
+ addMIMEType((short) 213, "application/vnd.motorola.flexsuite.ttc");
+ addMIMEType((short) 214, "application/vnd.motorola.flexsuite.wem");
+ addMIMEType((short) 215, "application/vnd.mozilla.xul+xml", "xul");
+ addMIMEType((short) 216, "application/vnd.ms-artgalry");
+ addMIMEType((short) 217, "application/vnd.ms-asf");
+ addMIMEType((short) 218, "application/vnd.ms-excel", "xls xlb xlt");
+ addMIMEType((short) 219, "application/vnd.ms-lrm");
+ addMIMEType((short) 220, "application/vnd.ms-pki.seccat", "cat");
+ addMIMEType((short) 221, "application/vnd.ms-pki.stl", "stl");
+ addMIMEType((short) 222, "application/vnd.ms-powerpoint", "ppt pps");
+ addMIMEType((short) 223, "application/vnd.ms-project");
+ addMIMEType((short) 224, "application/vnd.ms-tnef");
+ addMIMEType((short) 225, "application/vnd.ms-works");
+ addMIMEType((short) 226, "application/vnd.mseq");
+ addMIMEType((short) 227, "application/vnd.msign");
+ addMIMEType((short) 228, "application/vnd.music-niff");
+ addMIMEType((short) 229, "application/vnd.musician");
+ addMIMEType((short) 230, "application/vnd.netfpx");
+ addMIMEType((short) 231, "application/vnd.noblenet-directory");
+ addMIMEType((short) 232, "application/vnd.noblenet-sealer");
+ addMIMEType((short) 233, "application/vnd.noblenet-web");
+ addMIMEType((short) 234, "application/vnd.novadigm.EDM");
+ addMIMEType((short) 235, "application/vnd.novadigm.EDX");
+ addMIMEType((short) 236, "application/vnd.novadigm.EXT");
+ addMIMEType((short) 237, "application/vnd.oasis.opendocument.chart", "odc");
+ addMIMEType((short) 238, "application/vnd.oasis.opendocument.database", "odb");
+ addMIMEType((short) 239, "application/vnd.oasis.opendocument.formula", "odf");
+ addMIMEType((short) 240, "application/vnd.oasis.opendocument.graphics", "odg");
+ addMIMEType((short) 241, "application/vnd.oasis.opendocument.graphics-template", "otg");
+ addMIMEType((short) 242, "application/vnd.oasis.opendocument.image", "odi");
+ addMIMEType((short) 243, "application/vnd.oasis.opendocument.presentation", "odp");
+ addMIMEType((short) 244, "application/vnd.oasis.opendocument.presentation-template", "otp");
+ addMIMEType((short) 245, "application/vnd.oasis.opendocument.spreadsheet", "ods");
+ addMIMEType((short) 246, "application/vnd.oasis.opendocument.spreadsheet-template", "ots");
+ addMIMEType((short) 247, "application/vnd.oasis.opendocument.text", "odt");
+ addMIMEType((short) 248, "application/vnd.oasis.opendocument.text-master", "odm");
+ addMIMEType((short) 249, "application/vnd.oasis.opendocument.text-template", "ott");
+ addMIMEType((short) 250, "application/vnd.oasis.opendocument.text-web", "oth");
+ addMIMEType((short) 251, "application/vnd.osa.netdeploy");
+ addMIMEType((short) 252, "application/vnd.palm");
+ addMIMEType((short) 253, "application/vnd.pg.format");
+ addMIMEType((short) 254, "application/vnd.pg.osasli");
+ addMIMEType((short) 255, "application/vnd.powerbuilder6");
+ addMIMEType((short) 256, "application/vnd.powerbuilder6-s");
+ addMIMEType((short) 257, "application/vnd.powerbuilder7");
+ addMIMEType((short) 258, "application/vnd.powerbuilder7-s");
+ addMIMEType((short) 259, "application/vnd.powerbuilder75");
+ addMIMEType((short) 260, "application/vnd.powerbuilder75-s");
+ addMIMEType((short) 261, "application/vnd.previewsystems.box");
+ addMIMEType((short) 262, "application/vnd.publishare-delta-tree");
+ addMIMEType((short) 263, "application/vnd.pvi.ptid1");
+ addMIMEType((short) 264, "application/vnd.pwg-xhtml-print+xml");
+ addMIMEType((short) 265, "application/vnd.rapid");
+ addMIMEType((short) 266, "application/vnd.rim.cod", "cod");
+ addMIMEType((short) 267, "application/vnd.s3sms");
+ addMIMEType((short) 268, "application/vnd.seemail");
+ addMIMEType((short) 269, "application/vnd.shana.informed.formdata");
+ addMIMEType((short) 270, "application/vnd.shana.informed.formtemplate");
+ addMIMEType((short) 271, "application/vnd.shana.informed.interchange");
+ addMIMEType((short) 272, "application/vnd.shana.informed.package");
+ addMIMEType((short) 273, "application/vnd.smaf", "mmf");
+ addMIMEType((short) 274, "application/vnd.sss-cod");
+ addMIMEType((short) 275, "application/vnd.sss-dtf");
+ addMIMEType((short) 276, "application/vnd.sss-ntf");
+ addMIMEType((short) 277, "application/vnd.stardivision.calc", "sdc");
+ addMIMEType((short) 278, "application/vnd.stardivision.draw", "sda");
+ addMIMEType((short) 279, "application/vnd.stardivision.impress", "sdd sdp");
+ addMIMEType((short) 280, "application/vnd.stardivision.math", "smf");
+ addMIMEType((short) 281, "application/vnd.stardivision.writer", "sdw vor");
+ addMIMEType((short) 282, "application/vnd.stardivision.writer-global", "sgl");
+ addMIMEType((short) 283, "application/vnd.street-stream");
+ addMIMEType((short) 284, "application/vnd.sun.xml.calc", "sxc");
+ addMIMEType((short) 285, "application/vnd.sun.xml.calc.template", "stc");
+ addMIMEType((short) 286, "application/vnd.sun.xml.draw", "sxd");
+ addMIMEType((short) 287, "application/vnd.sun.xml.draw.template", "std");
+ addMIMEType((short) 288, "application/vnd.sun.xml.impress", "sxi");
+ addMIMEType((short) 289, "application/vnd.sun.xml.impress.template", "sti");
+ addMIMEType((short) 290, "application/vnd.sun.xml.math", "sxm");
+ addMIMEType((short) 291, "application/vnd.sun.xml.writer", "sxw");
+ addMIMEType((short) 292, "application/vnd.sun.xml.writer.global", "sxg");
+ addMIMEType((short) 293, "application/vnd.sun.xml.writer.template", "stw");
+ addMIMEType((short) 294, "application/vnd.svd");
+ addMIMEType((short) 295, "application/vnd.swiftview-ics");
+ addMIMEType((short) 296, "application/vnd.symbian.install", "sis");
+ addMIMEType((short) 297, "application/vnd.triscape.mxs");
+ addMIMEType((short) 298, "application/vnd.trueapp");
+ addMIMEType((short) 299, "application/vnd.truedoc");
+ addMIMEType((short) 300, "application/vnd.tve-trigger");
+ addMIMEType((short) 301, "application/vnd.ufdl");
+ addMIMEType((short) 302, "application/vnd.uplanet.alert");
+ addMIMEType((short) 303, "application/vnd.uplanet.alert-wbxml");
+ addMIMEType((short) 304, "application/vnd.uplanet.bearer-choice");
+ addMIMEType((short) 305, "application/vnd.uplanet.bearer-choice-wbxml");
+ addMIMEType((short) 306, "application/vnd.uplanet.cacheop");
+ addMIMEType((short) 307, "application/vnd.uplanet.cacheop-wbxml");
+ addMIMEType((short) 308, "application/vnd.uplanet.channel");
+ addMIMEType((short) 309, "application/vnd.uplanet.channel-wbxml");
+ addMIMEType((short) 310, "application/vnd.uplanet.list");
+ addMIMEType((short) 311, "application/vnd.uplanet.list-wbxml");
+ addMIMEType((short) 312, "application/vnd.uplanet.listcmd");
+ addMIMEType((short) 313, "application/vnd.uplanet.listcmd-wbxml");
+ addMIMEType((short) 314, "application/vnd.uplanet.signal");
+ addMIMEType((short) 315, "application/vnd.vcx");
+ addMIMEType((short) 316, "application/vnd.vectorworks");
+ addMIMEType((short) 317, "application/vnd.vidsoft.vidconference");
+ addMIMEType((short) 318, "application/vnd.visio", "vsd");
+ addMIMEType((short) 319, "application/vnd.vividence.scriptfile");
+ addMIMEType((short) 320, "application/vnd.wap.sic");
+ addMIMEType((short) 321, "application/vnd.wap.slc");
+ addMIMEType((short) 322, "application/vnd.wap.wbxml", "wbxml");
+ addMIMEType((short) 323, "application/vnd.wap.wmlc", "wmlc");
+ addMIMEType((short) 324, "application/vnd.wap.wmlscriptc", "wmlsc");
+ addMIMEType((short) 325, "application/vnd.webturbo");
+ addMIMEType((short) 326, "application/vnd.wrq-hp3000-labelled");
+ addMIMEType((short) 327, "application/vnd.wt.stf");
+ addMIMEType((short) 328, "application/vnd.xara");
+ addMIMEType((short) 329, "application/vnd.xfdl");
+ addMIMEType((short) 330, "application/vnd.yellowriver-custom-menu");
+ addMIMEType((short) 331, "application/x-123", "wk");
+ addMIMEType((short) 332, "application/x-abiword", "abw");
+ addMIMEType((short) 333, "application/x-apple-diskimage", "dmg");
+ addMIMEType((short) 334, "application/x-bcpio", "bcpio");
+ addMIMEType((short) 335, "application/x-bittorrent", "torrent");
+ addMIMEType((short) 336, "application/x-cdf", "cdf");
+ addMIMEType((short) 337, "application/x-cdlink", "vcd");
+ addMIMEType((short) 338, "application/x-chess-pgn", "pgn");
+ addMIMEType((short) 339, "application/x-core");
+ addMIMEType((short) 340, "application/x-cpio", "cpio");
+ addMIMEType((short) 341, "application/x-csh", "csh");
+ addMIMEType((short) 342, "application/x-debian-package", "deb udeb");
+ addMIMEType((short) 343, "application/x-director", "dcr dir dxr");
+ addMIMEType((short) 344, "application/x-dms", "dms");
+ addMIMEType((short) 345, "application/x-doom", "wad");
+ addMIMEType((short) 346, "application/x-dvi", "dvi");
+ addMIMEType((short) 347, "application/x-executable");
+ addMIMEType((short) 348, "application/x-flac", "flac");
+ addMIMEType((short) 349, "application/x-font", "pfa pfb gsf pcf pcf.Z");
+ addMIMEType((short) 350, "application/x-freemind", "mm");
+ addMIMEType((short) 351, "application/x-futuresplash", "spl");
+ addMIMEType((short) 352, "application/x-gnumeric", "gnumeric");
+ addMIMEType((short) 353, "application/x-go-sgf", "sgf");
+ addMIMEType((short) 354, "application/x-graphing-calculator", "gcf");
+ addMIMEType((short) 355, "application/x-gtar", "gtar tgz taz");
+ addMIMEType((short) 356, "application/x-hdf", "hdf");
+ addMIMEType((short) 357, "application/x-httpd-php", "phtml pht php");
+ addMIMEType((short) 358, "application/x-httpd-php-source", "phps");
+ addMIMEType((short) 359, "application/x-httpd-php3", "php3");
+ addMIMEType((short) 360, "application/x-httpd-php3-preprocessed", "php3p");
+ addMIMEType((short) 361, "application/x-httpd-php4", "php4");
+ addMIMEType((short) 362, "application/x-ica", "ica");
+ addMIMEType((short) 363, "application/x-internet-signup", "ins isp");
+ addMIMEType((short) 364, "application/x-iphone", "iii");
+ addMIMEType((short) 365, "application/x-iso9660-image", "iso");
+ addMIMEType((short) 366, "application/x-java-applet");
+ addMIMEType((short) 367, "application/x-java-bean");
+ addMIMEType((short) 368, "application/x-java-jnlp-file", "jnlp");
+ addMIMEType((short) 369, "application/x-javascript", "js");
+ addMIMEType((short) 370, "application/x-jmol", "jmz");
+ addMIMEType((short) 371, "application/x-kchart", "chrt");
+ addMIMEType((short) 372, "application/x-kdelnk");
+ addMIMEType((short) 373, "application/x-killustrator", "kil");
+ addMIMEType((short) 374, "application/x-koan", "skp skd skt skm");
+ addMIMEType((short) 375, "application/x-kpresenter", "kpr kpt");
+ addMIMEType((short) 376, "application/x-kspread", "ksp");
+ addMIMEType((short) 377, "application/x-kword", "kwd kwt");
+ addMIMEType((short) 378, "application/x-latex", "latex");
+ addMIMEType((short) 379, "application/x-lha", "lha");
+ addMIMEType((short) 380, "application/x-lzh", "lzh");
+ addMIMEType((short) 381, "application/x-lzx", "lzx");
+ addMIMEType((short) 382, "application/x-maker", "frm maker frame fm fb book fbdoc");
+ addMIMEType((short) 383, "application/x-mif", "mif");
+ addMIMEType((short) 384, "application/x-ms-wmd", "wmd");
+ addMIMEType((short) 385, "application/x-ms-wmz", "wmz");
+ addMIMEType((short) 386, "application/x-msdos-program", "com exe bat dll");
+ addMIMEType((short) 387, "application/x-msi", "msi");
+ addMIMEType((short) 388, "application/x-netcdf", "nc");
+ addMIMEType((short) 389, "application/x-ns-proxy-autoconfig", "pac");
+ addMIMEType((short) 390, "application/x-nwc", "nwc");
+ addMIMEType((short) 391, "application/x-object", "o");
+ addMIMEType((short) 392, "application/x-oz-application", "oza");
+ addMIMEType((short) 393, "application/x-pkcs7-certreqresp", "p7r");
+ addMIMEType((short) 394, "application/x-pkcs7-crl", "crl");
+ addMIMEType((short) 395, "application/x-python-code", "pyc pyo");
+ addMIMEType((short) 396, "application/x-quicktimeplayer", "qtl");
+ addMIMEType((short) 397, "application/x-redhat-package-manager", "rpm");
+ addMIMEType((short) 398, "application/x-rx");
+ addMIMEType((short) 399, "application/x-sh", "sh");
+ addMIMEType((short) 400, "application/x-shar", "shar");
+ addMIMEType((short) 401, "application/x-shellscript");
+ addMIMEType((short) 402, "application/x-shockwave-flash", "swf swfl");
+ addMIMEType((short) 403, "application/x-stuffit", "sit");
+ addMIMEType((short) 404, "application/x-sv4cpio", "sv4cpio");
+ addMIMEType((short) 405, "application/x-sv4crc", "sv4crc");
+ addMIMEType((short) 406, "application/x-tar", "tar");
+ addMIMEType((short) 407, "application/x-tcl", "tcl");
+ addMIMEType((short) 408, "application/x-tex-gf", "gf");
+ addMIMEType((short) 409, "application/x-tex-pk", "pk");
+ addMIMEType((short) 410, "application/x-texinfo", "texinfo texi");
+ addMIMEType((short) 411, "application/x-trash", "~ % bak old sik");
+ addMIMEType((short) 412, "application/x-troff", "t tr roff");
+ addMIMEType((short) 413, "application/x-troff-man", "man");
+ addMIMEType((short) 414, "application/x-troff-me", "me");
+ addMIMEType((short) 415, "application/x-troff-ms", "ms");
+ addMIMEType((short) 416, "application/x-ustar", "ustar");
+ addMIMEType((short) 417, "application/x-videolan");
+ addMIMEType((short) 418, "application/x-wais-source", "src");
+ addMIMEType((short) 419, "application/x-wingz", "wz");
+ addMIMEType((short) 420, "application/x-x509-ca-cert", "crt");
+ addMIMEType((short) 421, "application/x-xcf", "xcf");
+ addMIMEType((short) 422, "application/x-xfig", "fig");
+ addMIMEType((short) 423, "application/x-xpinstall", "xpi");
+ addMIMEType((short) 424, "audio/32kadpcm");
+ addMIMEType((short) 425, "audio/basic", "au snd");
+ addMIMEType((short) 426, "audio/g.722.1");
+ addMIMEType((short) 427, "audio/l16");
+ addMIMEType((short) 428, "audio/midi", "mid midi kar");
+ addMIMEType((short) 429, "audio/mp4a-latm");
+ addMIMEType((short) 430, "audio/mpa-robust");
+ addMIMEType((short) 431, "audio/mpeg", "mpga mpega mp2 mp3 m4a");
+ addMIMEType((short) 432, "audio/mpegurl", "m3u");
+ addMIMEType((short) 433, "audio/parityfec");
+ addMIMEType((short) 434, "audio/prs.sid", "sid");
+ addMIMEType((short) 435, "audio/telephone-event");
+ addMIMEType((short) 436, "audio/tone");
+ addMIMEType((short) 437, "audio/vnd.cisco.nse");
+ addMIMEType((short) 438, "audio/vnd.cns.anp1");
+ addMIMEType((short) 439, "audio/vnd.cns.inf1");
+ addMIMEType((short) 440, "audio/vnd.digital-winds");
+ addMIMEType((short) 441, "audio/vnd.everad.plj");
+ addMIMEType((short) 442, "audio/vnd.lucent.voice");
+ addMIMEType((short) 443, "audio/vnd.nortel.vbk");
+ addMIMEType((short) 444, "audio/vnd.nuera.ecelp4800");
+ addMIMEType((short) 445, "audio/vnd.nuera.ecelp7470");
+ addMIMEType((short) 446, "audio/vnd.nuera.ecelp9600");
+ addMIMEType((short) 447, "audio/vnd.octel.sbc");
+ addMIMEType((short) 448, "audio/vnd.qcelp");
+ addMIMEType((short) 449, "audio/vnd.rhetorex.32kadpcm");
+ addMIMEType((short) 450, "audio/vnd.vmx.cvsd");
+ addMIMEType((short) 451, "audio/x-aiff", "aif aiff aifc");
+ addMIMEType((short) 452, "audio/x-gsm", "gsm");
+ addMIMEType((short) 453, "audio/x-mpegurl", "m3u");
+ addMIMEType((short) 454, "audio/x-ms-wma", "wma");
+ addMIMEType((short) 455, "audio/x-ms-wax", "wax");
+ addMIMEType((short) 456, "audio/x-pn-realaudio-plugin");
+ addMIMEType((short) 457, "audio/x-pn-realaudio", "ra rm ram");
+ addMIMEType((short) 458, "audio/x-realaudio", "ra");
+ addMIMEType((short) 459, "audio/x-scpls", "pls");
+ addMIMEType((short) 460, "audio/x-sd2", "sd2");
+ addMIMEType((short) 461, "audio/x-wav", "wav");
+ addMIMEType((short) 462, "chemical/x-alchemy", "alc");
+ addMIMEType((short) 463, "chemical/x-cache", "cac cache");
+ addMIMEType((short) 464, "chemical/x-cache-csf", "csf");
+ addMIMEType((short) 465, "chemical/x-cactvs-binary", "cbin cascii ctab");
+ addMIMEType((short) 466, "chemical/x-cdx", "cdx");
+ addMIMEType((short) 467, "chemical/x-cerius", "cer");
+ addMIMEType((short) 468, "chemical/x-chem3d", "c3d");
+ addMIMEType((short) 469, "chemical/x-chemdraw", "chm");
+ addMIMEType((short) 470, "chemical/x-cif", "cif");
+ addMIMEType((short) 471, "chemical/x-cmdf", "cmdf");
+ addMIMEType((short) 472, "chemical/x-cml", "cml");
+ addMIMEType((short) 473, "chemical/x-compass", "cpa");
+ addMIMEType((short) 474, "chemical/x-crossfire", "bsd");
+ addMIMEType((short) 475, "chemical/x-csml", "csml csm");
+ addMIMEType((short) 476, "chemical/x-ctx", "ctx");
+ addMIMEType((short) 477, "chemical/x-cxf", "cxf cef");
+ addMIMEType((short) 478, "chemical/x-embl-dl-nucleotide", "emb embl");
+ addMIMEType((short) 479, "chemical/x-galactic-spc", "spc");
+ addMIMEType((short) 480, "chemical/x-gamess-input", "inp gam gamin");
+ addMIMEType((short) 481, "chemical/x-gaussian-checkpoint", "fch fchk");
+ addMIMEType((short) 482, "chemical/x-gaussian-cube", "cub");
+ addMIMEType((short) 483, "chemical/x-gaussian-input", "gau gjc gjf");
+ addMIMEType((short) 484, "chemical/x-gaussian-log", "gal");
+ addMIMEType((short) 485, "chemical/x-gcg8-sequence", "gcg");
+ addMIMEType((short) 486, "chemical/x-genbank", "gen");
+ addMIMEType((short) 487, "chemical/x-hin", "hin");
+ addMIMEType((short) 488, "chemical/x-isostar", "istr ist");
+ addMIMEType((short) 489, "chemical/x-jcamp-dx", "jdx dx");
+ addMIMEType((short) 490, "chemical/x-kinemage", "kin");
+ addMIMEType((short) 491, "chemical/x-macmolecule", "mcm");
+ addMIMEType((short) 492, "chemical/x-macromodel-input", "mmd mmod");
+ addMIMEType((short) 493, "chemical/x-mdl-molfile", "mol");
+ addMIMEType((short) 494, "chemical/x-mdl-rdfile", "rd");
+ addMIMEType((short) 495, "chemical/x-mdl-rxnfile", "rxn");
+ addMIMEType((short) 496, "chemical/x-mdl-sdfile", "sd sdf");
+ addMIMEType((short) 497, "chemical/x-mdl-tgf", "tgf");
+ addMIMEType((short) 498, "chemical/x-mmcif", "mcif");
+ addMIMEType((short) 499, "chemical/x-mol2", "mol2");
+ addMIMEType((short) 500, "chemical/x-molconn-Z", "b");
+ addMIMEType((short) 501, "chemical/x-mopac-graph", "gpt");
+ addMIMEType((short) 502, "chemical/x-mopac-input", "mop mopcrt mpc dat zmt");
+ addMIMEType((short) 503, "chemical/x-mopac-out", "moo");
+ addMIMEType((short) 504, "chemical/x-mopac-vib", "mvb");
+ addMIMEType((short) 505, "chemical/x-ncbi-asn1", "asn");
+ addMIMEType((short) 506, "chemical/x-ncbi-asn1-ascii", "prt ent");
+ addMIMEType((short) 507, "chemical/x-ncbi-asn1-binary", "val aso");
+ addMIMEType((short) 508, "chemical/x-ncbi-asn1-spec", "asn");
+ addMIMEType((short) 509, "chemical/x-pdb", "pdb ent");
+ addMIMEType((short) 510, "chemical/x-rosdal", "ros");
+ addMIMEType((short) 511, "chemical/x-swissprot", "sw");
+ addMIMEType((short) 512, "chemical/x-vamas-iso14976", "vms");
+ addMIMEType((short) 513, "chemical/x-vmd", "vmd");
+ addMIMEType((short) 514, "chemical/x-xtel", "xtel");
+ addMIMEType((short) 515, "chemical/x-xyz", "xyz");
+ addMIMEType((short) 516, "image/cgm");
+ addMIMEType((short) 517, "image/g3fax");
+ addMIMEType((short) 518, "image/gif", "gif");
+ addMIMEType((short) 519, "image/ief", "ief");
+ addMIMEType((short) 520, "image/jpeg", "jpeg jpg jpe");
+ addMIMEType((short) 521, "image/naplps");
+ addMIMEType((short) 522, "image/pcx", "pcx");
+ addMIMEType((short) 523, "image/png", "png");
+ addMIMEType((short) 524, "image/prs.btif");
+ addMIMEType((short) 525, "image/prs.pti");
+ addMIMEType((short) 526, "image/svg+xml", "svg svgz");
+ addMIMEType((short) 527, "image/tiff", "tiff tif");
+ addMIMEType((short) 528, "image/vnd.cns.inf2");
+ addMIMEType((short) 529, "image/vnd.djvu", "djvu djv");
+ addMIMEType((short) 530, "image/vnd.dwg");
+ addMIMEType((short) 531, "image/vnd.dxf");
+ addMIMEType((short) 532, "image/vnd.fastbidsheet");
+ addMIMEType((short) 533, "image/vnd.fpx");
+ addMIMEType((short) 534, "image/vnd.fst");
+ addMIMEType((short) 535, "image/vnd.fujixerox.edmics-mmr");
+ addMIMEType((short) 536, "image/vnd.fujixerox.edmics-rlc");
+ addMIMEType((short) 537, "image/vnd.mix");
+ addMIMEType((short) 538, "image/vnd.net-fpx");
+ addMIMEType((short) 539, "image/vnd.svf");
+ addMIMEType((short) 540, "image/vnd.wap.wbmp", "wbmp");
+ addMIMEType((short) 541, "image/vnd.xiff");
+ addMIMEType((short) 542, "image/x-cmu-raster", "ras");
+ addMIMEType((short) 543, "image/x-coreldraw", "cdr");
+ addMIMEType((short) 544, "image/x-coreldrawpattern", "pat");
+ addMIMEType((short) 545, "image/x-coreldrawtemplate", "cdt");
+ addMIMEType((short) 546, "image/x-corelphotopaint", "cpt");
+ addMIMEType((short) 547, "image/x-icon", "ico");
+ addMIMEType((short) 548, "image/x-jg", "art");
+ addMIMEType((short) 549, "image/x-jng", "jng");
+ addMIMEType((short) 550, "image/x-ms-bmp", "bmp");
+ addMIMEType((short) 551, "image/x-photoshop", "psd");
+ addMIMEType((short) 552, "image/x-portable-anymap", "pnm");
+ addMIMEType((short) 553, "image/x-portable-bitmap", "pbm");
+ addMIMEType((short) 554, "image/x-portable-graymap", "pgm");
+ addMIMEType((short) 555, "image/x-portable-pixmap", "ppm");
+ addMIMEType((short) 556, "image/x-rgb", "rgb");
+ addMIMEType((short) 557, "image/x-xbitmap", "xbm");
+ addMIMEType((short) 558, "image/x-xpixmap", "xpm");
+ addMIMEType((short) 559, "image/x-xwindowdump", "xwd");
+ addMIMEType((short) 560, "inode/chardevice");
+ addMIMEType((short) 561, "inode/blockdevice");
+ addMIMEType((short) 562, "inode/directory-locked");
+ addMIMEType((short) 563, "inode/directory");
+ addMIMEType((short) 564, "inode/fifo");
+ addMIMEType((short) 565, "inode/socket");
+ addMIMEType((short) 566, "message/delivery-status");
+ addMIMEType((short) 567, "message/disposition-notification");
+ addMIMEType((short) 568, "message/external-body");
+ addMIMEType((short) 569, "message/http");
+ addMIMEType((short) 570, "message/s-http");
+ addMIMEType((short) 571, "message/news");
+ addMIMEType((short) 572, "message/partial");
+ addMIMEType((short) 573, "message/rfc822");
+ addMIMEType((short) 574, "model/iges", "igs iges");
+ addMIMEType((short) 575, "model/mesh", "msh mesh silo");
+ addMIMEType((short) 576, "model/vnd.dwf");
+ addMIMEType((short) 577, "model/vnd.flatland.3dml");
+ addMIMEType((short) 578, "model/vnd.gdl");
+ addMIMEType((short) 579, "model/vnd.gs-gdl");
+ addMIMEType((short) 580, "model/vnd.gtw");
+ addMIMEType((short) 581, "model/vnd.mts");
+ addMIMEType((short) 582, "model/vnd.vtu");
+ addMIMEType((short) 583, "model/vrml", "wrl vrml");
+ addMIMEType((short) 584, "multipart/alternative");
+ addMIMEType((short) 585, "multipart/appledouble");
+ addMIMEType((short) 586, "multipart/byteranges");
+ addMIMEType((short) 587, "multipart/digest");
+ addMIMEType((short) 588, "multipart/encrypted");
+ addMIMEType((short) 589, "multipart/form-data");
+ addMIMEType((short) 590, "multipart/header-set");
+ addMIMEType((short) 591, "multipart/mixed");
+ addMIMEType((short) 592, "multipart/parallel");
+ addMIMEType((short) 593, "multipart/related");
+ addMIMEType((short) 594, "multipart/report");
+ addMIMEType((short) 595, "multipart/signed");
+ addMIMEType((short) 596, "multipart/voice-message");
+ addMIMEType((short) 597, "text/calendar", "ics icz");
+ addMIMEType((short) 598, "text/comma-separated-values", "csv");
+ addMIMEType((short) 599, "text/css", "css");
+ addMIMEType((short) 600, "text/directory");
+ addMIMEType((short) 601, "text/english");
+ addMIMEType((short) 602, "text/enriched");
+ addMIMEType((short) 603, "text/h323", "323");
+ addMIMEType((short) 604, "text/html", "html htm shtml");
+ addMIMEType((short) 605, "text/iuls", "uls");
+ addMIMEType((short) 606, "text/mathml", "mml");
+ addMIMEType((short) 607, "text/parityfec");
+ addMIMEType((short) 608, "text/plain", "asc txt text diff pot");
+ addMIMEType((short) 609, "text/prs.lines.tag");
+ addMIMEType((short) 610, "text/x-psp", "psp");
+ addMIMEType((short) 611, "text/rfc822-headers");
+ addMIMEType((short) 612, "text/richtext", "rtx");
+ addMIMEType((short) 613, "text/rtf", "rtf");
+ addMIMEType((short) 614, "text/scriptlet", "sct wsc");
+ addMIMEType((short) 615, "text/t140");
+ addMIMEType((short) 616, "text/texmacs", "tm ts");
+ addMIMEType((short) 617, "text/tab-separated-values", "tsv");
+ addMIMEType((short) 618, "text/uri-list");
+ addMIMEType((short) 619, "text/vnd.abc");
+ addMIMEType((short) 620, "text/vnd.curl");
+ addMIMEType((short) 621, "text/vnd.DMClientScript");
+ addMIMEType((short) 622, "text/vnd.flatland.3dml");
+ addMIMEType((short) 623, "text/vnd.fly");
+ addMIMEType((short) 624, "text/vnd.fmi.flexstor");
+ addMIMEType((short) 625, "text/vnd.in3d.3dml");
+ addMIMEType((short) 626, "text/vnd.in3d.spot");
+ addMIMEType((short) 627, "text/vnd.IPTC.NewsML");
+ addMIMEType((short) 628, "text/vnd.IPTC.NITF");
+ addMIMEType((short) 629, "text/vnd.latex-z");
+ addMIMEType((short) 630, "text/vnd.motorola.reflex");
+ addMIMEType((short) 631, "text/vnd.ms-mediapackage");
+ addMIMEType((short) 632, "text/vnd.sun.j2me.app-descriptor", "jad");
+ addMIMEType((short) 633, "text/vnd.wap.si");
+ addMIMEType((short) 634, "text/vnd.wap.sl");
+ addMIMEType((short) 635, "text/vnd.wap.wml", "wml");
+ addMIMEType((short) 636, "text/vnd.wap.wmlscript", "wmls");
+ addMIMEType((short) 637, "text/x-bibtex", "bib");
+ addMIMEType((short) 638, "text/x-c++hdr", "h++ hpp hxx hh");
+ addMIMEType((short) 639, "text/x-c++src", "c++ cpp cxx cc");
+ addMIMEType((short) 640, "text/x-chdr", "h");
+ addMIMEType((short) 641, "text/x-crontab");
+ addMIMEType((short) 642, "text/x-csh", "csh");
+ addMIMEType((short) 643, "text/x-csrc", "c");
+ addMIMEType((short) 644, "text/x-haskell", "hs");
+ addMIMEType((short) 645, "text/x-java", "java");
+ addMIMEType((short) 646, "text/x-literate-haskell", "lhs");
+ addMIMEType((short) 647, "text/x-makefile");
+ addMIMEType((short) 648, "text/x-moc", "moc");
+ addMIMEType((short) 649, "text/x-pascal", "p pas");
+ addMIMEType((short) 650, "text/x-pcs-gcd", "gcd");
+ addMIMEType((short) 651, "text/x-perl", "pl pm");
+ addMIMEType((short) 652, "text/x-python", "py");
+ addMIMEType((short) 653, "text/x-server-parsed-html");
+ addMIMEType((short) 654, "text/x-setext", "etx");
+ addMIMEType((short) 655, "text/x-sh", "sh");
+ addMIMEType((short) 656, "text/x-tcl", "tcl tk");
+ addMIMEType((short) 657, "text/x-tex", "tex ltx sty cls");
+ addMIMEType((short) 658, "text/x-vcalendar", "vcs");
+ addMIMEType((short) 659, "text/x-vcard", "vcf");
+ addMIMEType((short) 660, "video/dl", "dl");
+ addMIMEType((short) 661, "video/dv", "dif dv");
+ addMIMEType((short) 662, "video/fli", "fli");
+ addMIMEType((short) 663, "video/gl", "gl");
+ addMIMEType((short) 664, "video/mpeg", "mpeg mpg mpe");
+ addMIMEType((short) 665, "video/mp4", "mp4");
+ addMIMEType((short) 666, "video/quicktime", "qt mov");
+ addMIMEType((short) 667, "video/mp4v-es");
+ addMIMEType((short) 668, "video/parityfec");
+ addMIMEType((short) 669, "video/pointer");
+ addMIMEType((short) 670, "video/vnd.fvt");
+ addMIMEType((short) 671, "video/vnd.motorola.video");
+ addMIMEType((short) 672, "video/vnd.motorola.videop");
+ addMIMEType((short) 673, "video/vnd.mpegurl", "mxu");
+ addMIMEType((short) 674, "video/vnd.mts");
+ addMIMEType((short) 675, "video/vnd.nokia.interleaved-multimedia");
+ addMIMEType((short) 676, "video/vnd.vivo");
+ addMIMEType((short) 677, "video/x-la-asf", "lsf lsx");
+ addMIMEType((short) 678, "video/x-mng", "mng");
+ addMIMEType((short) 679, "video/x-ms-asf", "asf asx");
+ addMIMEType((short) 680, "video/x-ms-wm", "wm");
+ addMIMEType((short) 681, "video/x-ms-wmv", "wmv");
+ addMIMEType((short) 682, "video/x-ms-wmx", "wmx");
+ addMIMEType((short) 683, "video/x-ms-wvx", "wvx");
+ addMIMEType((short) 684, "video/x-msvideo", "avi");
+ addMIMEType((short) 685, "video/x-sgi-movie", "movie");
+ addMIMEType((short) 686, "x-conference/x-cooltalk", "ice");
+ addMIMEType((short) 687, "x-world/x-vrml", "vrm vrml wrl");
+ }
+
+ /** Guess a MIME type from a filename */
+ public static String guessMIMEType(String arg) {
+ int x = arg.lastIndexOf('.');
+ if(x == -1 || x == arg.length()-1)
+ return DEFAULT_MIME_TYPE;
+ String ext = arg.substring(x+1).toLowerCase();
+ Short mimeIndexOb = mimeTypesByExtension.get(ext);
+ if(mimeIndexOb != null) {
+ return mimeTypesByNumber.get(mimeIndexOb.intValue());
+ }
+ return DEFAULT_MIME_TYPE;
+ }
+
+ public static String getExtension(String type) {
+ short typeNumber = byName(type);
+ if(typeNumber < 0) return null;
+ return primaryExtensionByMimeNumber.get(typeNumber);
+ }
+
+ public static String[] getAllMIMETypes() {
+ return mimeTypesByNumber.toArray(new String[mimeTypesByNumber.size()]);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.swing.AbstractListModel;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: SortedListModel.java 338 2006-03-20 15:40:48Z bombe $
+ */
+public class SortedListModel extends AbstractListModel implements List {
+
+ private List elements = new ArrayList();
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSize() {
+ return size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getElementAt(int index) {
+ return elements.get(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void add(int index, Object element) {
+ elements.add(index, element);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean add(Object o) {
+ boolean result = elements.add(o);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addAll(Collection c) {
+ boolean result = elements.addAll(c);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addAll(int index, Collection c) {
+ boolean result = elements.addAll(index, c);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clear() {
+ elements.clear();
+ fireContentsChanged(this, 0, size());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean contains(Object o) {
+ return elements.contains(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsAll(Collection c) {
+ return elements.containsAll(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object o) {
+ return elements.equals(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object get(int index) {
+ return elements.get(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return elements.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int indexOf(Object o) {
+ return elements.indexOf(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator iterator() {
+ return elements.iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int lastIndexOf(Object o) {
+ return elements.lastIndexOf(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ListIterator listIterator() {
+ return elements.listIterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ListIterator listIterator(int index) {
+ return elements.listIterator(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object remove(int index) {
+ fireContentsChanged(this, 0, size());
+ return elements.remove(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean remove(Object o) {
+ fireContentsChanged(this, 0, size());
+ return elements.remove(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeAll(Collection c) {
+ fireContentsChanged(this, 0, size());
+ return elements.removeAll(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean retainAll(Collection c) {
+ fireContentsChanged(this, 0, size());
+ return elements.retainAll(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object set(int index, Object element) {
+ Object result = elements.set(index, element);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ return elements.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List subList(int fromIndex, int toIndex) {
+ return elements.subList(fromIndex, toIndex);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object[] toArray() {
+ return elements.toArray();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object[] toArray(Object[] a) {
+ return elements.toArray(a);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.awt.Component;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: TLabel.java 280 2006-03-17 20:24:27Z bombe $
+ */
+public class TLabel extends JLabel {
+
+ public TLabel() {
+ super();
+ }
+
+ public TLabel(int mnemonic, Component labelFor) {
+ super();
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(Icon image) {
+ super(image);
+ }
+
+ public TLabel(Icon image, int mnemonic, Component labelFor) {
+ super(image);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(Icon image, int horizontalAlignment) {
+ super(image);
+ }
+
+ public TLabel(Icon image, int horizontalAlignment, int mnemonic, Component labelFor) {
+ super(image);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(String text) {
+ super(text);
+ }
+
+ public TLabel(String text, int mnemonic, Component labelFor) {
+ super(text);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ setAlignmentX(0.0f);
+ }
+
+ public TLabel(String text, Icon icon, int horizontalAlignment) {
+ super(text, icon, horizontalAlignment);
+ }
+
+ public TLabel(String text, Icon icon, int horizontalAlignment, int mnemonic, Component labelFor) {
+ super(text, icon, horizontalAlignment);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(String text, int horizontalAlignment) {
+ super(text, horizontalAlignment);
+ }
+
+ public TLabel(String text, int horizontalAlignment, int mnemonic, Component labelFor) {
+ super(text, horizontalAlignment);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: TWizard.java 426 2006-03-29 18:02:50Z bombe $
+ */
+public class TWizard extends JFrame implements WindowListener {
+
+ protected List<WizardListener> wizardListeners = new ArrayList<WizardListener>();
+
+ private Action previousAction;
+ private Action nextAction;
+ private Action quitAction;
+ private JLabel pageIcon;
+ private JPanel pagePanel;
+ private JLabel pageHeading;
+ private JLabel pageDescription;
+
+ protected void frameInit() {
+ super.frameInit();
+ setResizable(false);
+ addWindowListener(this);
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ createActions();
+
+ pageIcon = new JLabel();
+ pageIcon.setVerticalAlignment(SwingConstants.TOP);
+ pageHeading = new JLabel();
+ pageHeading.setFont(pageHeading.getFont().deriveFont(pageHeading.getFont().getSize() * 2.0f).deriveFont(Font.BOLD));
+ pageDescription = new JLabel();
+
+ JPanel contentPane = new JPanel(new BorderLayout(12, 12));
+ contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
+
+ JPanel topPanel = new JPanel(new BorderLayout(12, 12));
+ contentPane.add(topPanel, BorderLayout.PAGE_START);
+
+ topPanel.add(pageIcon, BorderLayout.LINE_START);
+
+ JPanel textPanel = new JPanel(new BorderLayout(12, 12));
+ topPanel.add(textPanel, BorderLayout.CENTER);
+ textPanel.add(pageHeading, BorderLayout.PAGE_START);
+ textPanel.add(pageDescription, BorderLayout.CENTER);
+
+ pagePanel = new JPanel(new BorderLayout(12, 12));
+ contentPane.add(pagePanel, BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
+ buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12));
+ buttonPanel.add(new JButton(previousAction));
+ buttonPanel.add(new JButton(nextAction));
+ buttonPanel.add(new JButton(quitAction));
+ contentPane.add(buttonPanel, BorderLayout.PAGE_END);
+
+ setContentPane(contentPane);
+ }
+
+ @Override
+ public void pack() {
+ super.pack();
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2);
+ // System.out.println("resized to: " + getWidth() + "x" + getHeight());
+ }
+
+ private void createActions() {
+ previousAction = new AbstractAction("Previous") {
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionPrevious();
+ }
+ };
+
+ nextAction = new AbstractAction("Next") {
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionNext();
+ }
+ };
+
+ quitAction = new AbstractAction("Quit") {
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionQuit();
+ }
+ };
+ }
+
+ public void addWizardListener(WizardListener wizardListener) {
+ wizardListeners.add(wizardListener);
+ }
+
+ public void removeWizardListener(WizardListener wizardListener) {
+ wizardListeners.remove(wizardListener);
+ }
+
+ protected void fireWizardPreviousPressed() {
+ for (WizardListener wizardListener: wizardListeners) {
+ wizardListener.wizardPreviousPressed(this);
+ }
+ }
+
+ protected void fireWizardNextPressed() {
+ for (WizardListener wizardListener: wizardListeners) {
+ wizardListener.wizardNextPressed(this);
+ }
+ }
+
+ protected void fireWizardQuitPressed() {
+ for (WizardListener wizardListener: wizardListeners) {
+ wizardListener.wizardQuitPressed(this);
+ }
+ }
+
+ public void setIcon(Icon icon) {
+ pageIcon.setIcon(icon);
+ }
+
+ public void setPage(TWizardPage page) {
+ setVisible(false);
+ pageHeading.setText(page.getHeading());
+ pageDescription.setText(page.getDescription());
+ if (pagePanel.getComponentCount() > 0) {
+ if (pagePanel.getComponent(0) instanceof TWizardPage) {
+ ((TWizardPage) pagePanel.getComponent(0)).pageDeleted(this);
+ }
+ }
+ pagePanel.removeAll();
+ pagePanel.add(page, BorderLayout.CENTER);
+ page.pageAdded(this);
+ pack();
+ setTitle(page.getHeading());
+ setVisible(true);
+ }
+
+ public TWizardPage getPage() {
+ return (TWizardPage) pagePanel.getComponent(0);
+ }
+
+ public void setPreviousEnabled(boolean previousEnabled) {
+ previousAction.setEnabled(previousEnabled);
+ }
+
+ public void setPreviousName(String previousName) {
+ previousAction.putValue(Action.NAME, previousName);
+ }
+
+ public void setNextEnabled(boolean nextEnabled) {
+ nextAction.setEnabled(nextEnabled);
+ }
+
+ public void setNextName(String nextName) {
+ nextAction.putValue(Action.NAME, nextName);
+ }
+
+ public void setQuitEnabled(boolean quitEnabled) {
+ quitAction.setEnabled(quitEnabled);
+ }
+
+ public void setQuitName(String quitName) {
+ quitAction.putValue(Action.NAME, quitName);
+ }
+
+ protected void actionPrevious() {
+ fireWizardPreviousPressed();
+ }
+
+ protected void actionNext() {
+ fireWizardNextPressed();
+ }
+
+ protected void actionQuit() {
+ fireWizardQuitPressed();
+ }
+
+ //
+ // INTERFACE WindowListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowOpened(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowClosing(WindowEvent e) {
+ fireWizardQuitPressed();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowClosed(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowIconified(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowDeiconified(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowActivated(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowDeactivated(WindowEvent e) {
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import javax.swing.JPanel;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: TWizardPage.java 427 2006-03-29 18:03:06Z bombe $
+ */
+public class TWizardPage extends JPanel {
+
+ protected String heading;
+ protected String description;
+
+ public TWizardPage() {
+ }
+
+ public TWizardPage(String heading) {
+ this.heading = heading;
+ }
+
+ public TWizardPage(String heading, String description) {
+ this(heading);
+ this.description = description;
+ }
+
+ /**
+ * @return Returns the description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @param description
+ * The description to set.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * @return Returns the heading.
+ */
+ public String getHeading() {
+ return heading;
+ }
+
+ /**
+ * @param heading
+ * The heading to set.
+ */
+ public void setHeading(String heading) {
+ this.heading = heading;
+ }
+
+ public void pageAdded(TWizard wizard) {
+ }
+
+ public void pageDeleted(TWizard wizard) {
+ }
+
+}
--- /dev/null
+/*
+ * todesbaum-lib -
+ * Copyright (C) 2006 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.util.EventListener;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id: WizardListener.java 280 2006-03-17 20:24:27Z bombe $
+ */
+public interface WizardListener extends EventListener {
+
+ public void wizardNextPressed(TWizard wizard);
+ public void wizardPreviousPressed(TWizard wizard);
+ public void wizardQuitPressed(TWizard wizard);
+
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.xml;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * SimpleXML is a helper class to construct XML trees in a fast and simple way. Construct a new XML tree by calling {@link #SimpleXML(String)} and
+ * append new nodes by calling {@link #append(String)}.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id:SimpleXML.java 221 2006-03-06 14:46:49Z bombe $
+ */
+public class SimpleXML {
+
+ /**
+ * A {@link List} containing all child nodes of this node.
+ */
+ private List<SimpleXML> children = new ArrayList<SimpleXML>();
+
+ /**
+ * The name of this node.
+ */
+ private String name = null;
+
+ /**
+ * The value of this node.
+ */
+ private String value = null;
+
+ /**
+ * Constructs a new XML node without a name.
+ */
+ public SimpleXML() {
+ super();
+ }
+
+ /**
+ * Constructs a new XML node with the specified name.
+ *
+ * @param name
+ * The name of the new node
+ */
+ public SimpleXML(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the child node of this node with the specified name. If there are several child nodes with the specified name only the first node is
+ * returned.
+ *
+ * @param nodeName
+ * The name of the child node
+ * @return The child node, or <code>null</code> if there is no child node with the specified name
+ */
+ public SimpleXML getNode(String nodeName) {
+ for (int index = 0, count = children.size(); index < count; index++) {
+ if (children.get(index).name.equals(nodeName)) {
+ return children.get(index);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the child node that is specified by the names. The first element of <code>nodeNames</code> is the name of the child node of this
+ * node, the second element of <code>nodeNames</code> is the name of a child node's child node, and so on. By using this method you can descend
+ * into an XML tree pretty fast.
+ *
+ * <pre>
+ * SimpleXML deepNode = topNode.getNodes(new String[] { "person", "address", "number" });
+ * </pre>
+ *
+ * @param nodeNames
+ * @return A node that is a deep child of this node, or <code>null</code> if the specified node does not eixst
+ */
+ public SimpleXML getNode(String[] nodeNames) {
+ SimpleXML node = this;
+ for (String nodeName: nodeNames) {
+ node = node.getNode(nodeName);
+ }
+ return node;
+ }
+
+ /**
+ * Returns all child nodes of this node.
+ *
+ * @return All child nodes of this node
+ */
+ public SimpleXML[] getNodes() {
+ return getNodes(null);
+ }
+
+ /**
+ * Returns all child nodes of this node with the specified name. If there are no child nodes with the specified name an empty array is returned.
+ *
+ * @param nodeName
+ * The name of the nodes to retrieve, or <code>null</code> to retrieve all nodes
+ * @return All child nodes with the specified name
+ */
+ public SimpleXML[] getNodes(String nodeName) {
+ List<SimpleXML> resultList = new ArrayList<SimpleXML>();
+ for (SimpleXML child: children) {
+ if ((nodeName == null) || child.name.equals(nodeName)) {
+ resultList.add(child);
+ }
+ }
+ return resultList.toArray(new SimpleXML[resultList.size()]);
+ }
+
+ /**
+ * Appends a new XML node with the specified name and returns the new node. With this method you can create deep structures very fast.
+ *
+ * <pre>
+ * SimpleXML mouseNode = topNode.append("computer").append("bus").append("usb").append("mouse");
+ * </pre>
+ *
+ * @param nodeName
+ * The name of the node to append as a child to this node
+ * @return The new node
+ */
+ public SimpleXML append(String nodeName) {
+ return append(new SimpleXML(nodeName));
+ }
+
+ /**
+ * Appends a new XML node with the specified name and value and returns the new node.
+ *
+ * @param nodeName
+ * The name of the node to append
+ * @param nodeValue
+ * The value of the node to append
+ * @return The newly appended node
+ */
+ public SimpleXML append(String nodeName, String nodeValue) {
+ return append(nodeName).setValue(nodeValue);
+ }
+
+ /**
+ * Appends the node with all its child nodes to this node and returns the child node.
+ *
+ * @param newChild
+ * The node to append as a child
+ * @return The child node that was appended
+ */
+ public SimpleXML append(SimpleXML newChild) {
+ children.add(newChild);
+ return newChild;
+ }
+
+ public void remove(SimpleXML child) {
+ children.remove(child);
+ }
+
+ public void remove(String childName) {
+ SimpleXML child = getNode(childName);
+ if (child != null) {
+ remove(child);
+ }
+ }
+
+ public void replace(String childName, String value) {
+ remove(childName);
+ append(childName, value);
+ }
+
+ public void replace(SimpleXML childNode) {
+ remove(childNode.getName());
+ append(childNode);
+ }
+
+ public void removeAll() {
+ children.clear();
+ }
+
+ /**
+ * Sets the value of this node.
+ *
+ * @param nodeValue
+ * The new value of this node
+ * @return This node
+ */
+ public SimpleXML setValue(String nodeValue) {
+ value = nodeValue;
+ return this;
+ }
+
+ /**
+ * Returns the name of this node.
+ *
+ * @return The name of this node
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of this node.
+ *
+ * @return The value of this node
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Creates a {@link Document} from this node and all its child nodes.
+ *
+ * @return The {@link Document} created from this node
+ */
+ public Document getDocument() {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.newDocument();
+ Element rootElement = document.createElement(name);
+ document.appendChild(rootElement);
+ addChildren(rootElement);
+ return document;
+ } catch (ParserConfigurationException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Appends all children of this node to the specified {@link Element}. If a node has a value that is not <code>null</code> the value is
+ * appended as a text node.
+ *
+ * @param rootElement
+ * The element to attach this node's children to
+ */
+ private void addChildren(Element rootElement) {
+ for (SimpleXML child: children) {
+ Element childElement = rootElement.getOwnerDocument().createElement(child.name);
+ rootElement.appendChild(childElement);
+ if (child.value != null) {
+ Text childText = rootElement.getOwnerDocument().createTextNode(child.value);
+ childElement.appendChild(childText);
+ } else {
+ child.addChildren(childElement);
+ }
+ }
+ }
+
+ /**
+ * Creates a SimpleXML node from the specified {@link Document}. The SimpleXML node of the document's top-level node is returned.
+ *
+ * @param document
+ * The {@link Document} to create a SimpleXML node from
+ * @return The SimpleXML node created from the document's top-level node
+ */
+ public static SimpleXML fromDocument(Document document) {
+ SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName());
+ document.normalizeDocument();
+ return addDocumentChildren(xmlDocument, document.getFirstChild());
+ }
+
+ /**
+ * Appends the child nodes of the specified {@link Document} to this node. Text nodes are converted into a node's value.
+ *
+ * @param xmlDocument
+ * The SimpleXML node to append the child nodes to
+ * @param document
+ * The document whose child nodes to append
+ * @return The SimpleXML node the child nodes were appended to
+ */
+ private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) {
+ NodeList childNodes = document.getChildNodes();
+ for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) {
+ Node childNode = childNodes.item(childIndex);
+ if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text")) /*&& (childNode.getFirstChild().getNodeValue().trim().length() != 0)*/) {
+ xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue());
+ } else {
+ if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) {
+ SimpleXML newXML = xmlDocument.append(childNode.getNodeName());
+ addDocumentChildren(newXML, childNode);
+ }
+ }
+ }
+ return xmlDocument;
+ }
+
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * 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 for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Document;
+
+
+/**
+ * Contains method to transform DOM XML trees to byte arrays and vice versa.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id:XML.java 221 2006-03-06 14:46:49Z bombe $
+ */
+public class XML {
+
+ /** Cached document builder factory. */
+ private static DocumentBuilderFactory documentBuilderFactory = null;
+
+ /** Cached document builder. */
+ private static DocumentBuilder documentBuilder = null;
+
+ /** Cached transformer factory. */
+ private static TransformerFactory transformerFactory = null;
+
+ /** Does nothing. */
+ private XML() {
+ }
+
+ /**
+ * Returns a document builder factory. If possible the cached instance will be returned.
+ *
+ * @return A document builder factory
+ */
+ private static DocumentBuilderFactory getDocumentBuilderFactory() {
+ if (documentBuilderFactory != null) {
+ return documentBuilderFactory;
+ }
+ documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ return documentBuilderFactory;
+ }
+
+ /**
+ * Returns a document builder. If possible the cached instance will be returned.
+ *
+ * @return A document builder
+ */
+ private static DocumentBuilder getDocumentBuilder() {
+ if (documentBuilder != null) {
+ return documentBuilder;
+ }
+ try {
+ documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ }
+ return documentBuilder;
+ }
+
+ /**
+ * Returns a transformer factory. If possible the cached instance will be returned.
+ *
+ * @return A transformer factory
+ */
+ private static TransformerFactory getTransformerFactory() {
+ if (transformerFactory != null) {
+ return transformerFactory;
+ }
+ transformerFactory = TransformerFactory.newInstance();
+ return transformerFactory;
+ }
+
+ /**
+ * Creates a new XML document.
+ *
+ * @return A new XML document
+ */
+ public static Document createDocument() {
+ return getDocumentBuilder().newDocument();
+ }
+
+ /**
+ * Transforms the DOM XML document into a byte array.
+ *
+ * @param document
+ * The document to transform
+ * @return The byte array containing the XML representation
+ */
+ public static byte[] transformToByteArray(Document document) {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+ OutputStreamWriter converter = new OutputStreamWriter(byteOutput, Charset.forName("UTF-8"));
+ Result transformResult = new StreamResult(converter);
+ Source documentSource = new DOMSource(document);
+ try {
+ Transformer transformer = getTransformerFactory().newTransformer();
+ transformer.transform(documentSource, transformResult);
+ byteOutput.close();
+ return byteOutput.toByteArray();
+ } catch (IOException ioe1) {
+ } catch (TransformerConfigurationException tce1) {
+ } catch (TransformerException te1) {
+ } finally {
+ try {
+ byteOutput.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Transforms the byte array into a DOM XML document.
+ *
+ * @param data
+ * The byte array to parse
+ * @return The DOM XML document
+ */
+ public static Document transformToDocument(byte[] data) {
+ ByteArrayInputStream byteInput = new ByteArrayInputStream(data);
+ InputStreamReader converter = new InputStreamReader(byteInput, Charset.forName("UTF-8"));
+ Source xmlSource = new StreamSource(converter);
+ Result xmlResult = new DOMResult();
+ try {
+ Transformer transformer = getTransformerFactory().newTransformer();
+ transformer.transform(xmlSource, xmlResult);
+ return (Document) ((DOMResult) xmlResult).getNode();
+ } catch (TransformerConfigurationException tce1) {
+ } catch (TransformerException te1) {
+ } finally {
+ if (byteInput != null)
+ try {
+ byteInput.close();
+ } catch (IOException ioe1) {
+ }
+ if (converter != null)
+ try {
+ converter.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ return null;
+ }
+
+}