pax_global_header00006660000000000000000000000064132723103170014511gustar00rootroot0000000000000052 comment=b7c4c64cfddf46bdb7087f615493080bf9ef46bf util-V_2_8_BUILD_217/000077500000000000000000000000001327231031700142155ustar00rootroot00000000000000util-V_2_8_BUILD_217/.classpath000077500000000000000000000003531327231031700162040ustar00rootroot00000000000000 util-V_2_8_BUILD_217/.cvsignore000077500000000000000000000000151327231031700162140ustar00rootroot00000000000000bin releases util-V_2_8_BUILD_217/.gitignore000066400000000000000000000000261327231031700162030ustar00rootroot00000000000000releases /bin/ target util-V_2_8_BUILD_217/.project000077500000000000000000000005531327231031700156720ustar00rootroot00000000000000 util org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature util-V_2_8_BUILD_217/.settings/000077500000000000000000000000001327231031700161335ustar00rootroot00000000000000util-V_2_8_BUILD_217/.settings/org.eclipse.core.resources.prefs000066400000000000000000000001341327231031700243440ustar00rootroot00000000000000#Tue Jul 24 17:11:45 CEST 2007 eclipse.preferences.version=1 encoding/=ISO-8859-15 util-V_2_8_BUILD_217/.settings/org.eclipse.jdt.core.prefs000066400000000000000000000011511327231031700231130ustar00rootroot00000000000000#Sat Jan 17 00:37:32 CET 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.source=1.5 util-V_2_8_BUILD_217/LICENSE000066400000000000000000000636361327231031700152400ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! util-V_2_8_BUILD_217/build/000077500000000000000000000000001327231031700153145ustar00rootroot00000000000000util-V_2_8_BUILD_217/build/BUILD000077500000000000000000000001241327231031700160760ustar00rootroot00000000000000#Build Number for ANT. Do not edit! #Mon Apr 09 10:42:17 CEST 2018 build.number=216 util-V_2_8_BUILD_217/build/README000077500000000000000000000001031327231031700161710ustar00rootroot00000000000000A collection of small java helpers Copyright (C) 2004 Olaf Willuhn util-V_2_8_BUILD_217/build/RELEASE000077500000000000000000000000031327231031700163130ustar00rootroot000000000000002.7util-V_2_8_BUILD_217/build/build.xml000077500000000000000000000113261327231031700171430ustar00rootroot00000000000000 util-V_2_8_BUILD_217/pom.xml000066400000000000000000000053241327231031700155360ustar00rootroot00000000000000 4.0.0 de.willuhn.jameica jameica-util 2.6.7-SNAPSHOT Jameica Utility classes ISO-8859-1 ISO-8859-1 ISO-8859-1 1.7 1.7 src/ ${project.build.sourceDirectory} org.apache.maven.plugins maven-compiler-plugin 3.5.1 ${project.build.sourceEncoding} ${maven.compiler.source} ${maven.compiler.source} org.apache.maven.plugins maven-source-plugin attach-sources jar org.apache.maven.plugins maven-javadoc-plugin attach-javadocs jar doclint-java8-disable [1.8,) org.apache.maven.plugins maven-javadoc-plugin -Xdoclint:none util-V_2_8_BUILD_217/src/000077500000000000000000000000001327231031700150045ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/000077500000000000000000000000001327231031700153745ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/000077500000000000000000000000001327231031700170565ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/annotation/000077500000000000000000000000001327231031700212305ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/annotation/Inject.java000066400000000000000000000162271327231031700233170ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/annotation/Inject.java,v $ * $Revision: 1.6 $ * $Date: 2011/06/28 11:36:33 $ * $Author: willuhn $ * * Copyright (c) by willuhn - software & services * All rights reserved * **********************************************************************/ package de.willuhn.annotation; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.AccessibleObject; /** * Util-Klasse zum Setzen von Annotations. */ public class Inject { /** * Injiziert den Wert "value" in der Bean "bean" fuer all jene Attribute, * die mit Annotation "a" markiert sind. * @param bean die Bean, deren Attribute injiziert werden sollen. * @param a die gesucht Annotation. * @param value der zu setzende Wert. * @throws Exception Wenn beim Injizieren Fehler auftraten. */ public static void inject(Object bean, Class a, final Object value) throws Exception { inject(bean,new Injector() { public void inject(Object bean, AccessibleObject field, Annotation a) throws Exception { field.setAccessible(true); if (field instanceof Field) ((Field)field).set(bean,value); else if (field instanceof Method) ((Method)field).invoke(bean,value); else throw new Exception("unable to inject into " + field.getClass().getSimpleName()); } },a); } /** * Injiziert ein oder mehrere Werte in der Bean "bean" ueber den angegebenen Injector. * @param bean die Bean, deren Attribute injiziert werden sollen. * @param injector der Injector, der das Injizieren uebernehmen soll. * @throws Exception */ public static void inject(Object bean, Injector injector) throws Exception { inject(bean,injector,new Class[]{}); } /** * Injiziert ein oder mehrere Werte in der Bean "bean" ueber den angegebenen Injector. * @param bean die Bean, deren Attribute injiziert werden sollen. * @param injector der Injector, der das Injizieren uebernehmen soll. * @param annotations optionale Liste von Annotations, nach denen gesucht werden soll. * Sind keine angegeben, werden alle Annotations gefunden. * @throws Exception */ public static void inject(Object bean, Injector injector, Class... annotations) throws Exception { // Ich mag keine while(true)-Schleifen. Wenn die Abbruchbedingung // nicht erfuellt wird, haben wir eine Endlos-Schleife. Und da davon // auszugehen ist, dass eine Klasse unmoeglich mehr als 100 Superklassen // haben kann, limitieren wir das da. // Hier eigentlich nur fuer den Fall, dass es irgend eine Java-Implementierung gibt, // die bei Class#getSuperclass() nicht NULL liefert, wenn Class bereits ein // "java.lang.Object" ist (wir also schon oben angekommen sind). Ich hab // nirgends einen Hinweis gefunden, ob dieser spezifiziert ist. Class current = bean.getClass(); for (int i=0;i<100;++i) { ////////////////////////////////////////////////////////////////////////// // Member-Variablen Field[] fields = current.getDeclaredFields(); // getFields() liefert nur die public-Member if (fields != null && fields.length > 0) { for (Field f:fields) { Annotation[] al = f.getAnnotations(); // getDeclaredAnnotations() liefert keine geerbten Annotations if (al == null || al.length == 0) continue; // hat keine Annotations for (Annotation at:al) { if (matchTarget(at,ElementType.FIELD) && applicable(annotations,at)) { f.setAccessible(true); injector.inject(bean,f,at); break; // Eigentlich macht es keinen Sinn, einen Wert mehrfach zu setzen } } } } // ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Methoden Method[] methods = current.getDeclaredMethods(); if (methods != null && methods.length > 0) { for (Method m:methods) { Annotation[] al = m.getAnnotations(); if (al == null || al.length == 0) continue; for (Annotation at:al) { if (matchTarget(at,ElementType.METHOD) && applicable(annotations,at)) { m.setAccessible(true); injector.inject(bean,m,at); break; } } } } // ////////////////////////////////////////////////////////////////////////// Class superClass = current.getSuperclass(); if (superClass == null) break; // Oben angekommen // Ansonsten mit der Super-Klasse weitermachen current = superClass; } } /** * Prueft, ob die Annotation auf den angegebenen Typ passt. * @param a die zu pruefende Annotation. * @param type der zu pruefende Typ. * @return true, wenn entweder kein Target angegeben ist oder der Wert passt. */ private static boolean matchTarget(Annotation a, ElementType type) { Target target = a.getClass().getAnnotation(Target.class); if (target == null) return true; // Kein Target angegeben ElementType[] types = target.value(); if (types == null || types.length == 0) return true; for (ElementType t:types) { if (t.equals(type)) return true; } return false; } /** * Prueft, ob die Annotation angewendet werden soll. * @param list Liste der gesuchten Annotations. * @param a zu pruefende Annotation. * @return true, wenn "a" in "list" enthalten ist oder wenn "list" leer oder NULL ist. */ private static boolean applicable(Class[] list, Annotation a) { // die 3. Bedingung tritt bei "inject(bean,value,(Class)null)" ein if (list == null || list.length == 0 || (list.length == 1 && list[0] == null)) return true; for (Class test:list) { if (test == null) continue; if (a.annotationType().isAssignableFrom(test)) return true; } return false; } } /********************************************************************** * $Log: Inject.java,v $ * Revision 1.6 2011/06/28 11:36:33 willuhn * *** empty log message *** * * Revision 1.5 2011-06-28 11:03:25 willuhn * @N Inject unterstuetzt jetzt auch Methoden - nicht nur Member-Variablen * * Revision 1.4 2011-04-15 17:28:41 willuhn * @N Neue Funktion ohne Annotation-Parameter * @N die Liste der Annotationen konnte ein Null-Element enthalten, wurde nicht beachtet * * Revision 1.3 2011-03-30 12:23:21 willuhn * @N Das Injizieren kann der Injector jetzt selbst machen * * Revision 1.2 2011-03-30 11:54:53 willuhn * @N setAccessible fuer private Member * * Revision 1.1 2011-03-30 11:51:22 willuhn * @N Injector * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/annotation/Injector.java000066400000000000000000000026411327231031700236530ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/annotation/Injector.java,v $ * $Revision: 1.3 $ * $Date: 2011/06/28 11:03:25 $ * $Author: willuhn $ * * Copyright (c) by willuhn - software & services * All rights reserved * **********************************************************************/ package de.willuhn.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.AccessibleObject; /** * Interface fuer einen Injector, der die zu injizierenden Werte liefert. */ public interface Injector { /** * Injiziert den den Wert in die Bean. * @param bean die Bean, in die die Werte injiziert werden sollen. * @param field das Attribut oder die Methode, fuer welches der Wert gesetzt werden soll. * @param a die aktuelle Annotation. * @throws Exception */ public void inject(Object bean, AccessibleObject field, Annotation a) throws Exception; } /********************************************************************** * $Log: Injector.java,v $ * Revision 1.3 2011/06/28 11:03:25 willuhn * @N Inject unterstuetzt jetzt auch Methoden - nicht nur Member-Variablen * * Revision 1.2 2011-03-30 12:23:21 willuhn * @N Das Injizieren kann der Injector jetzt selbst machen * * Revision 1.1 2011-03-30 11:51:22 willuhn * @N Injector * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/annotation/Lifecycle.java000066400000000000000000000037221327231031700237760ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/annotation/Lifecycle.java,v $ * $Revision: 1.1 $ * $Date: 2011/06/28 09:54:16 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn software & services * All rights reserved * **********************************************************************/ package de.willuhn.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation, mit der der Lifecycle einer Bean festgelegt werden kann. * Es ist der Anwendung, die diesen Lifecycle auswertet, selbst ueberlassen, * welchen Lifecycle-Typ sie verwendet, wenn an der konkreten Bean * keine entsprechende Annotation definiert ist. */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Lifecycle { /** * Definiert die Licecycle-Typen. */ public static enum Type { /** * Bean-Instanz lebt fuer die Dauer der Anwendung. */ CONTEXT, /** * Bean-Instanz lebt fuer die Dauer der Session (des Users). */ SESSION, /** * Bean-Instanz lebt lediglich fuer die Dauer eines einzelnen Requests. */ REQUEST, } /** * Typ des Lifecycle. * @return Typ des Lifecycle */ Lifecycle.Type value(); } /********************************************************************* * $Log: Lifecycle.java,v $ * Revision 1.1 2011/06/28 09:54:16 willuhn * @N Lifecycle-Annotation aus jameica.webadmin in util verschoben * * Revision 1.2 2009/08/05 11:03:17 willuhn * @N Neue Annotation "Lifecycle" * * Revision 1.1 2009/08/05 09:03:40 willuhn * @C Annotations in eigenes Package verschoben (sind nicht mehr REST-spezifisch) * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/boot/000077500000000000000000000000001327231031700200215ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/boot/BootLoader.java000077500000000000000000000157011327231031700227250ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/boot/BootLoader.java,v $ * $Revision: 1.18 $ * $Date: 2011/09/26 11:41:36 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.boot; import java.util.HashMap; import java.util.Map; import java.util.Stack; import de.willuhn.logging.Logger; import de.willuhn.util.ProgressMonitor; /** * Der BootLoader. * Über diese Klasse kann ein kaskadierender Boot-Prozess gestartet werden. */ public class BootLoader { /** * Lookup der initialisierten Services. */ private Map services = new HashMap(); /** * Reihenfolge, in der die Services gebootet wurden. */ private Stack order = new Stack(); private int indent = 0; private ProgressMonitor dummy = new DummyMonitor(); private ProgressMonitor monitor = null; /** * Liefert den Progress-Monitor. * @return der Progress-Monitor. */ public final ProgressMonitor getMonitor() { return this.monitor == null ? this.dummy : this.monitor; } /** * Speichert den Progress-Monitor. * @param monitor Monitor, ueber den die Dienste ihre Informationen ueber den Boot-Vorgang ausgeben koennen. */ public final void setMonitor(ProgressMonitor monitor) { this.monitor = monitor; } /** * Liefert den gewuenschten Dienst und bootet das System * bei Bedarf bis genau zu diesem. * @param target das gweuenschte (ung ggf zu bootende) Ziel. * Bevor der Loader die Klasse target via init() * initialisiert, wird er alle Abhaengigkeiten aufloesen und zuvor alle * entsprechend depends angegebenen Services starten. * @return der instanziierte Dienst. */ public final T getBootable(Class target) { return (T) resolve(target,null); } /** * Loest die Abhnaegigkeiten fuer einen Dienst auf. * @param target der gewuenschte Dienst. * @param caller der Aufrufer. Kann null sein. * @return der instanziierte Dienst. * @throws Exception */ private final T resolve(Class target,Bootable caller) { // Target schon gebootet T s = (T) services.get(target); if (s != null) return s; Logger.debug(indent() + "booting service " + target.getName()); indent++; // Instanziieren try { s = (T) target.newInstance(); } catch (Exception e) { throw new RuntimeException("unable to create instance of " + target.getName(),e); } Logger.debug(indent() + "checking dependencies for " + target.getName()); Class[] deps = s.depends(); if (deps != null && deps.length > 0) { // Alle Abhaengigkeiten booten Logger.debug(indent() + "booting dependencies for " + target.getName()); for (Class dep:deps) { if (dep.equals(target)) { Logger.info(indent() + dep.getName() + " cannot have itself as dependency, skipping"); indent--; continue; } resolve(dep,s); } } else { Logger.debug(indent() + "no dependencies found for " + target.getName()); } // Abhaengigkeiten sind alle gebootet, jetzt koennen wir uns selbst initialisieren try { Logger.debug(indent() + "init service " + target.getName()); // Muss vor dem Initialisieren passieren, // damit der Service schon bekannt ist, wenn in Init jemand // den Service braucht -> wuerde sonst eine Rekursion ausloesen this.services.put(s.getClass(),s); long start = System.currentTimeMillis(); s.init(this,caller); this.order.add(s); long used = System.currentTimeMillis() - start; Logger.debug("used time to init " + target.getName() + ": " + used + " millis"); } catch (SkipServiceException e) { this.services.remove(s.getClass()); Logger.warn(indent() + "skipping service " + target.getName() + ". message: " + e.getMessage()); } indent--; return s; } /** * Liefert abhaengig von der Iterationstiefe eine definierte Anzahl von Leerzeichen. * @return Leerzeichen. */ private String indent() { String s = ""; for (int i=0;i 2) { params = new String[args.length - 2]; System.arraycopy(args,2,params,0,args.length-2); for (int i=0;iSie muessen ausserdem einen parameterlosen Konstruktor * mit dem Modifier public besitzen (siehe JavaBean-Spec.). */ public interface Bootable { /** * Wird vom BootLoader aufgerufen, wenn der Dienst initialisiert werden soll. * @param loader der Bootloader selbst. * @param caller der vorherige Dienst, welcher das init ausgeloest hat. * @throws SkipServiceException wenn der Service uebersprungen werden soll. * Die Exception kann vom Service bei der Initialisierung * geworfen werden, wenn diese zwar fehlschlug, sie jedoch * nicht dazu fuehren soll, dass der gesamte Boot-Prozess abgebrochen wird. * Stattdessen wird lediglich dieser Service uebersprungen. Um den gesamten * Boot-Prozess abzubrechen, muss folglich eine RuntimeException geworfen werden. */ public void init(BootLoader loader, Bootable caller) throws SkipServiceException; /** * Liste von Abhaengigkeiten in Form von Class-Objekten. * Die hier genannten Klassen werden vor der Initialisierung * dieses Services gestartet. * @return Abhaengigkeiten. * Die Class-Objekte muessen alle diese Interface Bootable implementieren. */ public Class[] depends(); /** * Wird aufgerufen, wenn die Anwendung beendet wird. * Hier kann der Dienst Aufraeum-Arbeiten vornehmen. */ public void shutdown(); } /********************************************************************** * $Log: Bootable.java,v $ * Revision 1.4 2010/11/11 16:24:08 willuhn * @N Bootloader ist jetzt getypt * * Revision 1.3 2006/04/26 09:37:07 web0 * @N bootloader redesign **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/boot/SkipServiceException.java000077500000000000000000000032401327231031700247740ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/boot/SkipServiceException.java,v $ * $Revision: 1.4 $ * $Date: 2010/11/11 16:24:08 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.boot; /** * Eine Exception, die von einem Service bei der Initialisierung * geworfen werden kann, wenn diese zwar fehlschlug, sie jedoch * nicht dazu fuehren soll, dass der gesamte Boot-Prozess abgebrochen wird. */ public class SkipServiceException extends Exception { private Bootable bootable = null; /** * ct. * @param bootable Dienst, der die Exception ausgeloest hat. * @param message Text. */ public SkipServiceException(Bootable bootable,String message) { super(message); this.bootable = bootable; } /** * ct. * @param bootable Dienst, der die Exception ausgeloest hat. * @param message Text. * @param cause */ public SkipServiceException(Bootable bootable,String message, Throwable cause) { super(message,cause); this.bootable = bootable; } /** * Liefert den Dienst, der den Fehler augeloest hat. * @return Dienst. */ public Bootable getBootable() { return bootable; } } /********************************************************************** * $Log: SkipServiceException.java,v $ * Revision 1.4 2010/11/11 16:24:08 willuhn * @N Bootloader ist jetzt getypt * * Revision 1.3 2005/03/09 01:06:21 web0 * @D javadoc fixes **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/boot/package.html000077500000000000000000000033371327231031700223130ustar00rootroot00000000000000

de.willuhn.boot ist ein kleines Framework zum Starten von Diensten/Services angelehnt an das SysV-Bootkonzept (bekannt aus Unix-Systemen).

Einsatzzweck: komplexere Java-Anwendungen, die beim Starten eine Reihe von Java-Klassen initialisieren müssen.
Typisches Beispiel - ein JSP-Server:

  • Starten des Server-Loops
    • Abhängigkeit: Starten des TCP-Managers
      • Abhängigkeit: Starten eines Pools von TCP-Listenern
      • Abhängigkeit: Starten eines Pools von TCP-Listenern mit SSL-Support
    • Abhängigkeit: Starten des Webapp-Managers
      • Abhängigkeit: Context für jedes gefundene WAR-Archiv starten
    • Abhängigkeit: Initialisieren des Handler
      • Abhängigkeit: JSP-Handler (matcht auf *.jsp und *.jsf)
      • Abhängigkeit: File-Handler (matcht auf *.*)
    • Abhängigkeit: Starten des JSP-Compilers
Es sind also eine Reihe von Services zu initialisieren, die voneinander abhängig sind.

Ziele:

  • Beim Starten eines Services muss der Bootloader selbständig alle abhängigen und somit vorher zu startenden Dienste auflösen.
  • Jeder Service muss hierbei nur seine direkten Abhängigkeiten kennen. Alle daraus resultierenden weiteren Abhängigkeiten muss der Bottloader selbst erkennen.

util-V_2_8_BUILD_217/src/de/willuhn/io/000077500000000000000000000000001327231031700174655ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/io/AbstractZipSupport.java000066400000000000000000000041361327231031700241570ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/io/AbstractZipSupport.java,v $ * $Revision: 1.2 $ * $Date: 2010/12/07 16:01:53 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.io; import de.willuhn.util.ProgressMonitor; /** * Abstrakte Basisklasse fuer ZIP-Support. * @author willuhn */ public class AbstractZipSupport { protected ProgressMonitor monitor = new DummyMonitor(); /** * Legt den Progress-Monitor fest, ueber den Ausgaben waehrend des Packens/Entpackens ausgegeben werden sollen. * Wird dieser nicht definiert, werden keine Ausgaben vorgenommen. * @param monitor */ public void setMonitor(ProgressMonitor monitor) { if (monitor != null) this.monitor = monitor; } /** * Dummy-Implementierung. */ private class DummyMonitor implements ProgressMonitor { /** * @see de.willuhn.util.ProgressMonitor#setPercentComplete(int) */ public void setPercentComplete(int percent) {} /** * @see de.willuhn.util.ProgressMonitor#addPercentComplete(int) */ public void addPercentComplete(int percent) {} /** * @see de.willuhn.util.ProgressMonitor#getPercentComplete() */ public int getPercentComplete() {return 0;} /** * @see de.willuhn.util.ProgressMonitor#setStatus(int) */ public void setStatus(int status) {} /** * @see de.willuhn.util.ProgressMonitor#setStatusText(java.lang.String) */ public void setStatusText(String text) {} /** * @see de.willuhn.util.ProgressMonitor#log(java.lang.String) */ public void log(String msg) {} } } /********************************************************************* * $Log: AbstractZipSupport.java,v $ * Revision 1.2 2010/12/07 16:01:53 willuhn * @N IOUtil * * Revision 1.1 2008/03/07 00:46:53 willuhn * @N ZipCreator * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/io/CSVFile.java000077500000000000000000000065151327231031700215750ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/io/CSVFile.java,v $ * $Revision: 1.4 $ * $Date: 2011/04/12 11:28:19 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.io; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; /** * Parser fuer CSV-Dateien. */ public class CSVFile { private String separator = ";"; private BufferedReader reader = null; private String currentLine = null; private boolean recall = false; private boolean prev = false; /** * ct. * @param file die CSV-Datei. */ public CSVFile(InputStream file) { this(file,null); } /** * ct. * @param file die CSV-Datei. * @param separator Trennzeichen. */ public CSVFile(InputStream file,String separator) { this.reader = new BufferedReader(new InputStreamReader(file)); if (separator != null) this.separator = separator; } /** * ct. * @param file die CSV-Datei. * @param separator Trennzeichen. * @param encoding das Encoding. * @throws UnsupportedEncodingException */ public CSVFile(InputStream file, String separator, String encoding) throws UnsupportedEncodingException { this.reader = new BufferedReader(new InputStreamReader(file,encoding)); if (separator != null) this.separator = separator; } /** * Prueft, ob weitere Zeilen vorhanden sind. * Der interne Pointer rueckt durch Aufruf dieser Funktion nicht * weiter. Die Funktion kann also mehrmals hintereinander aufgerufen * werden. Der Reader rueckt erst durch Aufruf der Funktion next() * weiter. * @return true, wenn noch Zeilen vorhanden sind, sonst false. * @throws IOException */ public synchronized boolean hasNext() throws IOException { // Wenn die Funktion mehrmals aufgerufen wird, ohne dass // zwischendurch mal ein next() gemacht wurde, wollen wir // nicht weitersteppen if (recall) return prev; prev = ((currentLine = reader.readLine()) != null); recall = true; return prev; } /** * Liefert die naechste Zeile der Datei. * @return naechste Zeile. * @throws IOException */ public synchronized String[] next() throws IOException { if (!hasNext()) throw new IOException("no more lines"); String[] cols = currentLine.split(separator+"(?=([^\"]*\"[^\"]*\")*(?![^\"]*\"))"); recall = false; // recall flag zuruecksetzen return cols; } /** * Schliesst die CSV-Datei. * @throws IOException */ public void close() throws IOException { reader.close(); } } /********************************************************************** * $Log: CSVFile.java,v $ * Revision 1.4 2011/04/12 11:28:19 willuhn * @N Konstruktor zur expliziten Angabe des Encodings * * Revision 1.3 2005/10/25 22:34:39 web0 * @C CSV-Reader auf Regex umgestellt * * Revision 1.2 2005/03/09 01:06:20 web0 * @D javadoc fixes * * Revision 1.1 2004/10/07 18:06:10 willuhn * @N ZipExtractor * * Revision 1.1 2004/09/17 14:36:59 willuhn * @N CSVFile * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/io/FileCopy.java000077500000000000000000000061411327231031700220470ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/io/FileCopy.java,v $ * $Revision: 1.2 $ * $Date: 2010/03/11 10:20:22 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.io; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; /** * Zum Dateien kopieren. */ public class FileCopy { /** * Kopiert die Quell-Datei zur Ziel-Datei. * Wenn es sich beim Ziel um ein Verzeichnis handelt, wird die Quell- * Datei in dieses Verzeichnis kopiert. Handelt es sich bei dem Ziel * um eine Datei, wird sie gegen die Quelle ersetzt bzw. neu erstellt. * @param from Quelle. * @param to Ziel. * @param force Ohne Warnung ueberschreiben, falls die Zieldatei bereits existiert. * @throws IOException Wenn beim Kopieren ein Fehler auftrat * @throws FileExistsException wenn die Zieldatei existiert und force false ist. */ public static void copy(File from, File to, boolean force) throws IOException, FileExistsException { if (from == null || to == null) throw new IOException("source or target is null"); if (!from.canRead()) throw new IOException("read permission failed in " + from.getAbsolutePath()); if (to.isDirectory() && !to.exists()) throw new IOException("target directory " + to.getAbsolutePath() + " does not exist"); if (to.isFile() && to.exists() && !to.canWrite()) throw new IOException("write permission failed in " + to.getAbsolutePath()); if (to.isFile() && to.exists() && !force) throw new FileExistsException("file " + to.getAbsolutePath() + " allready exists"); if (to.isDirectory()) to = new File(to,from.getName()); FileChannel srcChannel = null; FileChannel dstChannel = null; try { srcChannel = new FileInputStream(from).getChannel(); dstChannel = new FileOutputStream(to).getChannel(); dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); } finally { try { if (srcChannel != null) srcChannel.close(); } catch (IOException e) { /* useless */ } try { if (dstChannel != null) dstChannel.close(); } catch (IOException e) { /* useless */ } } } /** * Wird geworfen, wenn eine Datei ueberschrieben werden soll, die bereits existiert. */ public static class FileExistsException extends Exception { /** * Erzeugt eine neue Exception dieses Typs mit der genannten Meldung. * @param message anzuzeigende Meldung. */ public FileExistsException(String message) { super(message); } } } /********************************************************************** * $Log: FileCopy.java,v $ * Revision 1.2 2010/03/11 10:20:22 willuhn * @B NPE * * Revision 1.1 2004/10/07 18:06:10 willuhn * @N ZipExtractor * * Revision 1.1 2004/01/04 18:45:45 willuhn * @N FileCopy * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/io/FileFinder.java000077500000000000000000000121321327231031700223410ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/io/FileFinder.java,v $ * $Revision: 1.3 $ * $Date: 2007/04/19 00:01:26 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.io; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; /** * Hilfsklasse zum (rekursiven) Suchen von Dateien. */ public class FileFinder { private File baseDir = null; private ArrayList contains = new ArrayList(); private ArrayList found = new ArrayList(); /** * ct. * @param baseDir Verzeichnis, ab dem gesucht werden soll. */ public FileFinder(File baseDir) { this.baseDir = baseDir; } /** * Suchkriterium via OR hinzufuegen. * Die Datei muss den genannten String im Detainamen enthalten. * Wird diese Funktion mehrmals aufgerufen, werden alle * Suchkriterien mit ODER verknuepft. * @param regex Regulaerer Ausdruck. */ public void matches(String regex) { if (regex == null || "".equals(regex)) return; contains.add(regex); } /** * Suchkriterium via OR hinzufuegen. * Die Datei muss die genannte Dateiendung haben. * Ob die Dateiendung hierbei mit fuehrendem Punkt oder ohne angegeben wird, spielt keine Rolle. * Wird diese Funktion mehrmals aufgerufen, werden alle * Suchkriterien mit ODER verknuepft. * @param extension Datei-Endung. zb "jar" oder ".jar". */ public void extension(String extension) { if (extension == null || "".equals(extension)) return; if (extension.startsWith(".")) extension = extension.substring(1); contains.add(".*?\\."+extension+"$"); } /** * Sucht im aktuellen Verzeichnis und liefert das Ergebnis zurueck. * Hinweis: Die Funktion liefert nur Dateien, keine Verzeichnisse. * @return Liste der gefundenen Dateien. */ public File[] find() { find(this.baseDir,false,false); return (File[]) found.toArray(new File[found.size()]); } /** * Sucht rekursiv ab dem aktuellen Verzeichnis und liefert das Ergebnis zurueck. * Hinweis: Die Funktion liefert nur Dateien, keine Verzeichnisse. * @return Liste der gefundenen Dateien. */ public File[] findRecursive() { find(this.baseDir,true,false); return (File[]) found.toArray(new File[found.size()]); } /** * Sucht im aktuellen Verzeichnis und liefert das Ergebnis zurueck. * @return Liste der gefundenen Dateien und Verzeichnisse. */ public File[] findAll() { find(this.baseDir,false,true); return (File[]) found.toArray(new File[found.size()]); } /** * Sucht rekursiv ab dem aktuellen Verzeichnis und liefert das Ergebnis zurueck. * @return Liste der gefundenen Dateien und Verzeichnisse. */ public File[] findAllRecursive() { find(this.baseDir,true, true); return (File[]) found.toArray(new File[found.size()]); } /** * interne Suchfunktion. * @param dir Verzeichnis, ab dem gesucht werden soll. * @param recursive true, wenn rekursiv gesucht werden soll. * @param all true, wenn auch Verzeichnisse gefunden werden sollen. */ private void find(File dir, boolean recursive, final boolean all) { if (dir == null || !dir.canRead()) return; // Alle Dateien des Verzeichnisses suchen File[] files = dir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { File f = new File(dir,name); if (!all && !f.isFile()) return false; if (contains.size() == 0) { // es wurden keine Filter definiert, also matcht alles return true; } String regex = null; for (int i=0;i 0) // Nur schreiben, wenn wirklich was gelesen wurde { os.write(b,0,read); r += read; } } return r; } /** * Schliesst Streams. * Ggf. auftretende Exceptions werden nicht weitergeworfen sondern nur geloggt. * @param closeables Liste zu schliessender Streams. NULL wird toleriert. * @return true, wenn das Schliessen erfolgreich war, sonst false. */ public static boolean close(Closeable... closeables) { boolean ok = true; if (closeables == null || closeables.length == 0) return ok; for (Closeable c:closeables) { try { if (c != null) c.close(); } catch (Throwable t) { Logger.error("error while closing stream",t); ok = false; } } return ok; } } /********************************************************************** * $Log: IOUtil.java,v $ * Revision 1.3 2010/12/07 16:09:43 willuhn * @N NULL tolerieren * * Revision 1.2 2010-12-07 16:07:10 willuhn * @N Mehrere Streams schliessen * * Revision 1.1 2010-12-07 16:01:53 willuhn * @N IOUtil * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/io/LineOutputStream.java000077500000000000000000000060271327231031700236240ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/io/LineOutputStream.java,v $ * $Revision: 1.1 $ * $Date: 2004/11/12 18:18:19 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.io; import java.io.IOException; import java.io.OutputStream; /** * Ein OutputStream, der alle Daten, die erhaelt buffert und zeilenweise * an writeLine(java.lang.String) uebergibt. Sprich: Will * man Daten zeilenweise verarbeiten, darf aber nur einen OutputStream * angeben, dann kann man von dieser Klasse ableiten, die Funktion writeLine * implementieren und kann bequem zeilenweise lesen. * Hinweis: Ist die Zeile laenger als der angegebene Buffer, wird bei Erreichen * der Buffer-Groesse auch schon vor dem Zeilenende geschrieben. */ public abstract class LineOutputStream extends OutputStream { private int bufferSize = 1024; private char[] buffer; private StringBuffer line = new StringBuffer(); private int bufferCount = 0; /** * Erzeugt einen LineOutputStream mit 1024 Byte Buffer. */ public LineOutputStream() { this(1024); } /** * Erzeugt einen LineOutputStream mit der angebenen Buffer-Groesse. * @param bufferSize Buffer-Groesse in Bytes. */ public LineOutputStream(int bufferSize) { super(); this.bufferSize = bufferSize; buffer = new char[bufferSize]; } /** * @see java.io.OutputStream#write(int) */ public final void write(int b) throws IOException { // Wenn ein Linebreak kommt, schreiben wir raus if (b == '\n') { line.append(buffer); writeLine(line.toString().replaceAll("\\r|\\n","")); line = new StringBuffer(); bufferCount = 0; buffer = new char[bufferSize]; return; } // Meistens schreiben wir in den Char-Buffer if (bufferCount < bufferSize) { buffer[bufferCount++] = (char) b; return; } // Charbuffer ist voll, wir haengens an die Zeile line.append(buffer); bufferCount = 0; buffer = new char[bufferSize]; } /** * Wird aufgerufen, wenn eine Zeile vollstaendig ist und * geschrieben werden kann oder aber der Buffer voll ist. * Wichtig: In der Zeile ggf. vorhandene Linewraps werden * entfernt. Sollen Die Ausgaben also z.Bsp. via System.out * geschrieben werden, dann bitte "println()" statt "print()" * verwenden, um den entfernten Zeilenumbruch wieder anzufuegen. * @param s der zu schreibende String bereinigt um seinen Zeilenumbruch. * @throws IOException */ public abstract void writeLine(String s) throws IOException; } /********************************************************************** * $Log: LineOutputStream.java,v $ * Revision 1.1 2004/11/12 18:18:19 willuhn * @C Logging refactoring * * Revision 1.1 2004/11/10 17:48:49 willuhn * *** empty log message *** * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/io/ZipCreator.java000066400000000000000000000106361327231031700224200ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/io/ZipCreator.java,v $ * $Revision: 1.2 $ * $Date: 2010/12/07 16:01:53 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn software & services * All rights reserved * **********************************************************************/ package de.willuhn.io; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import de.willuhn.util.ProgressMonitor; /** * Hilfsklasse zum Erzeugen von ZIP-Dateien. */ public class ZipCreator extends AbstractZipSupport { private ZipOutputStream target = null; /** * @param os der OutputStream, in den die ZIP-Daten geschrieben werden sollen. * Der OutputStream wird intern nicht gepuffert, es sollte also bereits * ein BufferedOutputStream uebergeben werden. Ausserdem muss der ZipCreator * explizit durch Aufruf von close() geschlossen werden, da * er ja nicht selbst erkennen kann, wann alle Dateien hinzugefuegt wurden. * Das ist WICHTIG, da die ZIP-Datei sonst nicht lesbar ist. */ public ZipCreator(OutputStream os) { this.target = new ZipOutputStream(os); } /** * Schliesst den ZipCreator und den zugehoerigen OutputStream. * @throws IOException */ public void close() throws IOException { if (this.target != null) { try { this.target.close(); monitor.setPercentComplete(100); monitor.setStatusText("zip file created successfully"); monitor.setStatus(ProgressMonitor.STATUS_DONE); } catch (IOException e) { monitor.setStatus(ProgressMonitor.STATUS_ERROR); throw e; } } } private boolean running = false; /** * Fuegt der ZIP-Datei ein Verzeichnis/eine Datei hinzu. * Wenn es sich um ein Verzeichnis handelt, wird es rekursiv samt allen enthaltenen Dateien hinzugefuegt. * @param entry das hinzuzufuegende Verzeichnis/die Datei. * @throws IOException */ public void add(File entry) throws IOException { _add(entry.getName(),entry); } /** * Fuegt der ZIP-Datei ein Verzeichnis/eine Datei hinzu. * Wenn es sich um ein Verzeichnis handelt, wird es rekursiv samt allen enthaltenen Dateien hinzugefuegt. * @param zipPath der Pfad, in dem die Datei gespeichert werden soll. * @param handle das hinzuzufuegende Verzeichnis/die Datei. * @throws IOException */ private void _add(String zipPath, File handle) throws IOException { if (!handle.exists()) return; // Das koennen wir tolierieren if (!handle.canRead()) throw new IOException("cannot read " + handle.getAbsolutePath()); // Status beim ersten Aufruf setzen if (!running) { monitor.setStatus(ProgressMonitor.STATUS_RUNNING); running = true; } // Verzeichnisse fuegen wir rekursiv hinzu. // Als Basis-Pfad gilt das oberste. if (handle.isDirectory()) { File[] children = handle.listFiles(); if (children.length == 0) { // Leeres Verzeichnis. Legen wir trotzdem an // Verzeichnis selbst anlegen. Mit Slash am Ende // damit es als Verzeichnis anerkannt wird this.target.putNextEntry(new ZipEntry(zipPath + "/")); this.target.closeEntry(); return; } for (int i=0;iclose()-Methode aufgerufen. */ public ZipExtractor(ZipFile zip) { this.zip = zip; } /** * Entpackt das ZIP-File in das angegebene Verzeichnis. * Bereits existierende Dateien/Verzeichnisse werden nur dann ueberschrieben, wenn sie neuer sind. * @param targetDirectory Ziel-Verzeichnis. * Es wird automatisch angelegt, wenn es noch nicht existiert. * @throws IOException */ public void extract(File targetDirectory) throws IOException { monitor.setStatus(ProgressMonitor.STATUS_RUNNING); monitor.setStatusText("extracting zip file " + zip.getName() + " to " + targetDirectory.getAbsolutePath()); monitor.log("extracting zip file " + zip.getName() + " to " + targetDirectory.getAbsolutePath()); Logger.info("extracting zip file " + zip.getName() + " to " + targetDirectory.getAbsolutePath()); if (!targetDirectory.exists()) { monitor.log("creating directory " + targetDirectory.getAbsolutePath()); if (!targetDirectory.mkdirs()) throw new IOException("unable to create target directory " + targetDirectory.getAbsolutePath()); } // Liste aller Elemente des ZIP holen. Enumeration entries = zip.entries(); // Ueber die Anzahl der Elemente in der ZIP-Datei haben wir // einen Anhaltspunkt fuer die Fortschrittsanzeige. int size = zip.size(); monitor.log("uncompressing " + size + " elements"); String currentName = null; File currentFile = null; File backup = null; int i = 0; try { // Iterieren und entpacken. while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); currentName = entry.getName(); // Fortschritt neu berechnen monitor.setPercentComplete(i * 100 / size); i++; currentFile = new File(targetDirectory,currentName); Logger.info(currentName); // Issn Verzeichnis, legen wir ggf. an. if (entry.isDirectory()) { if (!currentFile.exists()) { Logger.debug(" creating directory"); currentFile.mkdirs(); } else { Logger.info(" directory allready exists, skipping"); } continue; } // Die Dateien kommen nicht in der idealen Reihenfolge. // Es kann also passieren, dass zuerst eine Datei kommt, // das Verzeichnis, in dem sie sich befindet, aber erst // danach. In diesem Fall wuerde es zu einem Fehler // beim Schreiben der Datei kommen. Also ermitteln wir // von jeder Datei erst das Verzeichnis und erstellen // es bei Bedarf vorher noch schnell. int idx = currentName.lastIndexOf('/'); if (idx >= 0) { // jepp, wir haben ein Verzeichnis, mal sehn ob's // existiert. String path = currentName.substring(0, idx); File f = new File(targetDirectory,path); if (!f.exists()) { Logger.debug(" creating directory"); if (!f.mkdirs()) throw new IOException("unable to create directory " + f.getAbsolutePath()); } } // Wir ueberschreiben ggf. durch aktuellere Dateien. Um das "sicher" // zu machen, erstellen wir von jeder Datei vorm Ueberschreiben ein // Backup das wir nach erfolgreichem Entpacken loeschen. if (currentFile.exists()) { long zipTime = entry.getTime(); long fileTime = currentFile.lastModified(); if (zipTime > fileTime) { Logger.info(" zip entry is newer, replacing"); backup = new File(currentFile.getAbsolutePath() + ".bak"); currentFile.renameTo(backup); // umbenennen currentFile = new File(targetDirectory,currentName); // wir erzeugen eine neue Referenz } else { Logger.info(" skipping, allready exists"); continue; } } // Issne Datei, neu erzeugen. monitor.log(currentFile.getAbsolutePath()); if (!currentFile.createNewFile()) throw new IOException("unable to create file " + currentFile.getAbsolutePath()); InputStream is = zip.getInputStream(entry); if (is == null) { Logger.warn(" entry " + entry.getName() + " not found in archive, skipping"); continue; } OutputStream os = new BufferedOutputStream(new FileOutputStream(currentFile)); IOUtil.copy(is,os); is.close(); os.flush(); os.close(); if (backup != null && backup.exists()) backup.delete(); } monitor.setPercentComplete(100); monitor.setStatusText("zip file " + zip.getName() + " uncompressed successfully"); monitor.setStatus(ProgressMonitor.STATUS_DONE); } catch (IOException e) { monitor.setStatus(ProgressMonitor.STATUS_ERROR); // Wenn es irgends zu einem Fehler kommt, benennen wir die ggf. letzte // existierende Backup-Datei schnell noch wieder zurueck try { if (backup != null && currentFile != null && backup.exists() && backup.isFile()) { String name = currentFile.getAbsolutePath(); if (currentFile.exists() && currentFile.isFile()) currentFile.delete(); backup.renameTo(new File(name)); } } catch (Throwable t2) { // useless } throw e; } finally { if (zip != null) { try { zip.close(); } catch (Exception e) { // useless } } } } } /********************************************************************* * $Log: ZipExtractor.java,v $ * Revision 1.11 2010/12/07 16:01:53 willuhn * @N IOUtil * * Revision 1.10 2009/06/12 11:12:44 willuhn * @N Falls ZIP-Entries kaputte Umlaute haben, kann es vorkommen, dass der zugehoerige InputStream nicht gefunden wird. Das warf eine NPE - jetzt werden die Entries (mit Warnung im Log) uebersprungen * * Revision 1.9 2008/12/17 00:47:49 willuhn * *** empty log message *** * * Revision 1.8 2008/12/16 16:11:30 willuhn * @N Uebersichtlichere Log-Ausgaben * * Revision 1.7 2008/03/07 00:46:53 willuhn * @N ZipCreator * * Revision 1.6 2005/07/15 08:53:17 web0 * *** empty log message *** * * Revision 1.5 2005/03/09 01:06:20 web0 * @D javadoc fixes * * Revision 1.4 2004/11/04 22:41:46 willuhn * *** empty log message *** * * Revision 1.3 2004/11/04 17:48:31 willuhn * *** empty log message *** * * Revision 1.2 2004/10/08 00:19:25 willuhn * *** empty log message *** * * Revision 1.1 2004/10/07 18:06:10 willuhn * @N ZipExtractor * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/logging/000077500000000000000000000000001327231031700205045ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/logging/JavaLoggingHandler.java000066400000000000000000000064301327231031700250400ustar00rootroot00000000000000/********************************************************************** * * Copyright (c) by Olaf Willuhn * GPLv2 * **********************************************************************/ package de.willuhn.logging; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.logging.Handler; import java.util.logging.LogManager; import java.util.logging.LogRecord; /** * Ein Handler, der "java.util.logging.Handler" implementiert, damit Log-Ausgaben * von Java in unser Logging umgeleitet werden koennen. * Die Klasse muss nicht manuell instanziiert werden. Es genuegt ein * Class.forName("de.willuhn.logging.JavaLoggingHandler"); * an passender Stelle. Der Handler registriert sich dann automatisch * an allen gefundenen Loggern. */ public class JavaLoggingHandler extends Handler { private final static Handler singleton = new JavaLoggingHandler(); private static Map logMapping = new HashMap(); static { try { logMapping.put(java.util.logging.Level.CONFIG,Level.INFO); logMapping.put(java.util.logging.Level.FINE,Level.DEBUG); logMapping.put(java.util.logging.Level.FINER,Level.DEBUG); logMapping.put(java.util.logging.Level.FINEST,Level.TRACE); logMapping.put(java.util.logging.Level.INFO,Level.INFO); logMapping.put(java.util.logging.Level.SEVERE,Level.ERROR); logMapping.put(java.util.logging.Level.WARNING,Level.WARN); // Wir deaktivieren alle Logger von Java java.util.logging.Logger logger = java.util.logging.Logger.getLogger(""); Handler[] handlers = logger.getHandlers(); if (handlers != null) { for (int i=0;inull. */ public static Level findByName(String name) { return (Level) registry.get(name); } /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { return ((Level)obj).value == this.value; } /** * @see java.lang.Object#toString() */ public String toString() { return "Name: " + name + ", Level: " + value; } } /********************************************************************** * $Log: Level.java,v $ * Revision 1.4 2005/03/24 17:28:25 web0 * @B bug in Level.findByName * * Revision 1.3 2005/03/09 01:06:20 web0 * @D javadoc fixes * * Revision 1.2 2005/01/14 00:49:04 willuhn * *** empty log message *** * * Revision 1.1 2004/11/12 18:18:19 willuhn * @C Logging refactoring * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/logging/Logger.java000077500000000000000000000231071327231031700225740ustar00rootroot00000000000000/********************************************************************** * * Copyright (c) by Olaf Willuhn * GPLv2 * **********************************************************************/ package de.willuhn.logging; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Date; import de.willuhn.logging.targets.Target; import de.willuhn.util.History; import de.willuhn.util.Queue; import de.willuhn.util.Queue.QueueFullException; /** * Kleiner System-Logger. * @author willuhn */ public class Logger { // maximale Groesse des Log-Puffers (Zeilen-Anzahl) private final static int BUFFER_SIZE = 200; // Die Liste der Log-Targets private static ArrayList targets = new ArrayList(); // Eine History mit den letzten Log-Eintraegen. Kann ganz nuetzlich sein, // wenn man irgendwo in der Anwendung mal die letzten Zeilen des Logs ansehen will. private static History lastLines = new History(BUFFER_SIZE); private static Level level = Level.DEFAULT; private static LoggerThread lt = null; static { lt = new LoggerThread("Logger-Thread"); lt.start(); } /** * Fuegt der Liste der Ausgabe-Targets ein weiteres hinzu. * @param target Ausgabe-Target. */ public static void addTarget(Target target) { if (target == null) return; synchronized (targets) { targets.add(target); } } /** * Entfernt ein Target aus der Liste. * @param target zu entfernendes Target. */ public static void removeTarget(Target target) { if (target == null) return; synchronized(targets) { targets.remove(target); } } /** * Setzt den Log-Level. * @param level Log-Level. */ public static void setLevel(Level level) { if (level == null) return; Logger.level = level; } /** * Liefert den aktuellen Log-Level. * @return Log-Level. */ public static Level getLevel() { return level; } /** * Prueft, ob Meldungen mit dem angegeben Log-Level derzeit geloggt werden. * @param l das zu testende Log-Level. * @return true, wenn Meldungen mit dem angegeben Log-Level derzeit geloggt werden. */ public static boolean isLogging(Level l) { return l != null && l.getValue() >= Logger.level.getValue(); } /** * Schreibt eine Message vom Typ "trace" ins Log. * @param message zu loggende Nachricht. */ public static void trace(String message) { write(Level.TRACE,message); } /** * Schreibt eine Message vom Typ "debug" ins Log. * @param message zu loggende Nachricht. */ public static void debug(String message) { write(Level.DEBUG,message); } /** * Schreibt eine Message vom Typ "info" ins Log. * @param message zu loggende Nachricht. */ public static void info(String message) { write(Level.INFO,message); } /** * Schreibt eine Message vom Typ "warn" ins Log. * @param message zu loggende Nachricht. */ public static void warn(String message) { write(Level.WARN,message); } /** * Schreibt eine Message vom Typ "error" ins Log. * @param message zu loggende Nachricht. */ public static void error(String message) { write(Level.ERROR,message); } /** * Schreibt den Fehler ins Log. * @param message zu loggende Nachricht. * @param t Exception oder Error. */ public static void error(String message, Throwable t) { write(Level.ERROR,message,t); } /** * Flusht die noch nicht geschriebenen Log-Meldungen. * Eigentlich macht die Funktion nichts anderes, als solange * zu warten, bis die Queue leer ist ;). * @throws InterruptedException */ public static void flush() throws InterruptedException { while(lt.messages.size() > 0) { Thread.sleep(100l); } } /** * Schliesst den Logger und die damit verbundene Log-Datei. */ public static void close() { lt.shutdown(); // Wir muessen noch etwas warten, bis der Thread alle Eintraege // aus der Queue geschrieben hat. try { while (!lt.finished()) { Thread.sleep(50); } } catch (Exception e) { e.printStackTrace(); lt.interrupt(); } synchronized (targets) { Target target = null; for (int i=0;i= retryCount) { println("***** [WARN] Logger queue full, writing to STDOUT *****"); println(msg.toString()); return; } try { messages.push(msg); return; } catch (QueueFullException e) { // try again ;) } } } /** * Beendet den Logger-Thread. */ private void shutdown() { this.quit = true; } /** * Liefert true, wenn der Thread die letzten Meldungen rausgeschrieben hat. * @return true, wenn alles rausgeschrieben ist. */ private boolean finished() { return finished; } /** * Gibt den Text auf STDOUT aus. * @param text auszugebender Text. */ private void println(String text) { try { System.out.println(text); } catch (Exception e) { // ignore - wenn STDOUT kaputt ist, koennen wir uns eh nicht mehr artikulieren ;) } } /** * @see java.lang.Runnable#run() */ public void run() { Message msg = null; while(true) { if (messages.size() == 0 && quit) { finished = true; return; } if (messages.size() == 0) { // nichts zum Schreiben da, dann warten wir etwas try { sleep(100); } catch (InterruptedException e) { } continue; } msg = (Message) messages.pop(); Target target = null; synchronized (targets) { if (targets.size() == 0) { println(msg.toString()); continue; } for (int i=0;inull wenn es Localhost ist oder er nicht angegeben ist. * @return der Hostname oder null. */ public String getHost() { return this.host; } /** * Liefert die eigentliche Nachricht. * @return Nachricht. */ public String getText() { return text; } /** * Liefert den Namen des Threads. * @return thread der Name des Threads. */ public String getThread() { return thread; } /** * Liefert den Namen der loggenden Klasse. * @return Name der loggenden Klasse. */ public String getLoggingClass() { return clazz; } /** * Liefert den Namen der loggenden Methode. * @return Name der loggenden Methode. */ public String getLoggingMethod() { return method; } /** * @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer(); if (this.host != null && this.host.length() > 0) { sb.append("["); sb.append(host); sb.append("]"); } if (this.date != null) { sb.append("["); sb.append(this.date.toString()); sb.append("]"); } if (this.level != null) { sb.append("["); sb.append(this.level.getName()); sb.append("]"); } if (this.thread != null) { sb.append("["); sb.append(this.thread); sb.append("]"); } if (clazz != null && method != null) { sb.append("["); sb.append(clazz); sb.append("."); sb.append(method); sb.append("]"); } sb.append(" "); sb.append(text); return sb.toString(); } } /********************************************************************** * $Log: Message.java,v $ * Revision 1.4 2008/06/13 13:48:17 willuhn * @R removed unused import * * Revision 1.3 2008/06/13 13:48:01 willuhn * @N Hostname mit ausgeben * * Revision 1.2 2008/06/13 13:40:47 willuhn * @N Class und Method kann nun explizit angegeben werden * @N Hostname kann mitgeloggt werden * * Revision 1.1 2004/12/31 19:34:22 willuhn * @C some logging refactoring * @N syslog support for logging * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/logging/targets/000077500000000000000000000000001327231031700221555ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/logging/targets/LogrotateTarget.java000077500000000000000000000143271327231031700261410ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/logging/targets/LogrotateTarget.java,v $ * $Revision: 1.6 $ * $Date: 2009/06/07 22:05:54 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by bbv AG * All rights reserved * **********************************************************************/ package de.willuhn.logging.targets; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.zip.GZIPOutputStream; import de.willuhn.io.FileCopy; import de.willuhn.logging.Logger; import de.willuhn.logging.Message; /** * Implementierung eines Targets, welches nach einer definierten Dateigroesse * das Log-File rotiert und optional zippt. * @author willuhn */ public class LogrotateTarget implements Target { private File file = null; private OutputStream os = null; private boolean append = true; private boolean skipRotate = false; private long maxLength = 1L * 1024L * 1024L; private boolean zip = true; private final static DateFormat DF = new SimpleDateFormat("yyyyMMdd-HHmm_ss"); private final static String lineSep = System.getProperty("line.separator"); /** * ct. * @param target Die Ziel-Datei. * @param append Legt fest, ob an das Log angehaengt oder ueberschrieben werden soll. * @throws IOException */ public LogrotateTarget(File target, boolean append) throws IOException { this.file = target; this.append = append; this.os = new FileOutputStream(this.file,this.append); } /** * Legt die Maximal-Groesse des Log-Files fest, nach dessen * Erreichen es rotiert werden soll. * Default-Groesse: 1MB. * @param length Angabe der Maximalgroesse in Bytes. */ public void setMaxLength(long length) { this.maxLength = length; } /** * Legt fest, ob die rotierten Logs gezippt werden sollen. * Default: Aktiv. * @param zip */ public void setZip(boolean zip) { this.zip = zip; } /** * @see de.willuhn.logging.targets.Target#write(de.willuhn.logging.Message) */ public void write(Message message) throws Exception { if (message == null) return; checkRotate(); os.write((message.toString() + lineSep).getBytes()); } /** * @see de.willuhn.logging.targets.Target#close() */ public void close() throws Exception { os.close(); } /** * Prueft die Dateigroesse und rotiert ggf. * @throws IOException */ private synchronized void checkRotate() throws IOException { if (skipRotate) return; synchronized(os) { if (this.file.length() < this.maxLength) return; Logger.info("rotating log file " + this.file.getAbsolutePath()); Logger.debug("closing old log file"); os.close(); String name = this.file.getName(); if (zip) { File archiveFile = new File(this.file.getParent(),name + "-" + DF.format(new Date()) + ".gz"); Logger.info("compressing old log file to " + archiveFile.getAbsolutePath()); OutputStream os = null; InputStream is = null; try { os = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(archiveFile))); is = new BufferedInputStream(new FileInputStream(this.file)); byte[] buf = new byte[4096]; int read = 0; do { read = is.read(buf); if (read > 0) os.write(buf,0,read); } while(read != -1); Logger.info("old log file compressed"); } catch (Throwable t) { Logger.error("error while rotating logfile, disable rotating",t); skipRotate = true; } finally { if (os != null) { try { os.close(); } catch (Exception e) { Logger.error("error while closing outputstream, disable rotating"); skipRotate = true; } } if (is != null) { try { is.close(); } catch (Exception e) { Logger.error("error while closing inputstream, disable rotating"); skipRotate = true; } } } } else { File archiveFile = new File(this.file.getParent(),name + "-" + DF.format(new Date())); Logger.info("copying log file to " + archiveFile.getAbsolutePath()); try { FileCopy.copy(this.file,archiveFile,true); } catch (FileCopy.FileExistsException e) { Logger.error("unable to copy log file, disable rotating",e); skipRotate = true; } } Logger.info("deleting old log file"); if (this.file.delete()) { Logger.info("creating new log file " + name); this.file = new File(this.file.getParent(),name); } else { Logger.error("unable to delete old log file " + name + ", disable rotating"); skipRotate = true; } this.os = new FileOutputStream(this.file,this.append); Logger.info("logrotation done"); } } } /********************************************************************* * $Log: LogrotateTarget.java,v $ * Revision 1.6 2009/06/07 22:05:54 willuhn * @N Logfile-Rotate ausschalten, wenn es fehlschlug - koennte sonst eine Rekursion ausloesen * * Revision 1.5 2007/03/26 23:52:08 willuhn * @N plattform specific line separator in logfiles * * Revision 1.4 2006/03/23 14:02:47 web0 * @N new logrotate mechanism (runs no longer in background) * * Revision 1.3 2005/08/16 21:42:02 web0 * @N support for appending to log files * * Revision 1.2 2005/08/09 14:27:36 web0 * *** empty log message *** * * Revision 1.1 2005/08/09 14:09:26 web0 * @N added logrotate target * *********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/logging/targets/OutputStreamTarget.java000077500000000000000000000032011327231031700266420ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/logging/targets/OutputStreamTarget.java,v $ * $Revision: 1.2 $ * $Date: 2007/03/26 23:52:08 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.logging.targets; import java.io.OutputStream; import de.willuhn.logging.Message; /** * Target, welches in einen OutputStream schreibt. */ public class OutputStreamTarget implements Target { private OutputStream os = null; private final static String lineSep = System.getProperty("line.separator"); /** * ct. * @param os OutputStream, in den geschrieben werden soll. */ public OutputStreamTarget(OutputStream os) { this.os = os; } /** * @see de.willuhn.logging.targets.Target#write(de.willuhn.logging.Message) */ public void write(Message message) throws Exception { if (message == null) return; os.write((message.toString() + lineSep).getBytes()); } /** * @see de.willuhn.logging.targets.Target#close() */ public void close() throws Exception { os.close(); } } /********************************************************************** * $Log: OutputStreamTarget.java,v $ * Revision 1.2 2007/03/26 23:52:08 willuhn * @N plattform specific line separator in logfiles * * Revision 1.1 2004/12/31 19:34:22 willuhn * @C some logging refactoring * @N syslog support for logging * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/logging/targets/SyslogTarget.java000077500000000000000000000047541327231031700254640ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/logging/targets/SyslogTarget.java,v $ * $Revision: 1.1 $ * $Date: 2004/12/31 19:34:22 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.logging.targets; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import de.willuhn.logging.Logger; import de.willuhn.logging.Message; /** * Target, welches an einen Syslog-Server loggen kann. */ public class SyslogTarget implements Target { private int port = 514; private InetAddress targetHost = null; private DatagramSocket socket = null; /** * ct. * @param hostname Hostname des Servers, auf dem der Syslog-Server laeuft. * Ist dieser nicht angegeben, wird an Localhost geloggt. * Als Port wird 514 verwendet. * @throws Exception */ public SyslogTarget(String hostname) throws Exception { this(hostname,514); } /** * ct. * @param hostname Hostname des Servers, auf dem der Syslog-Server laeuft. * Ist dieser nicht angegeben, wird an Localhost geloggt. * @param port UDP-Port, an den gesendet werden soll. * @throws Exception */ public SyslogTarget(String hostname, int port) throws Exception { try { targetHost = InetAddress.getByName(hostname); } catch (Exception e) { Logger.warn("hostname " + hostname + " invalid, trying localhost"); targetHost = InetAddress.getByName("localhost"); } this.port = port; this.socket = new DatagramSocket(); } /** * @see de.willuhn.logging.targets.Target#write(de.willuhn.logging.Message) */ public void write(Message message) throws Exception { if (message == null) return; String s = "[" + message.getLevel().getName() + "] " + message.getText(); byte[] data = s.getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, targetHost, port); socket.send(packet); } /** * @see de.willuhn.logging.targets.Target#close() */ public void close() throws Exception { socket.close(); } } /********************************************************************** * $Log: SyslogTarget.java,v $ * Revision 1.1 2004/12/31 19:34:22 willuhn * @C some logging refactoring * @N syslog support for logging * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/logging/targets/Target.java000077500000000000000000000021541327231031700242530ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/logging/targets/Target.java,v $ * $Revision: 1.1 $ * $Date: 2004/12/31 19:34:22 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.logging.targets; import de.willuhn.logging.Message; /** * Basis-Interface aller Logging-Ziele. */ public interface Target { /** * Schreibt die uebergebene Nachricht in das Logging-Target. * @param message zu loggende Nachricht. * @throws Exception */ public void write(Message message) throws Exception; /** * Schliesst das Target. * @throws Exception */ public void close() throws Exception; } /********************************************************************** * $Log: Target.java,v $ * Revision 1.1 2004/12/31 19:34:22 willuhn * @C some logging refactoring * @N syslog support for logging * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/net/000077500000000000000000000000001327231031700176445ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/net/MulticastClient.java000066400000000000000000000153621327231031700236220ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/net/MulticastClient.java,v $ * $Revision: 1.2 $ * $Date: 2007/11/27 18:52:56 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn software & services * All rights reserved * **********************************************************************/ package de.willuhn.net; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import de.willuhn.logging.Logger; /** * Eine kleine Hilfsklasse fuer RMI Multicast-Discovery. */ public class MulticastClient { /** * Default-Multicast-Adresse. */ public final static String DEFAULT_ADDRESS = "224.0.0.1"; /** * Default-Port. */ public final static int DEFAULT_PORT = 6789; private InetAddress self = null; private int port = DEFAULT_PORT; private InetAddress address = null; private DatagramPacket packet = null; private MulticastSocket socket = null; private Worker worker = null; /** * Erzeugt einen neuen Listener auf der Standard-Adresse mit dem Standard-Port. * @throws IOException */ public MulticastClient() throws IOException { this(DEFAULT_ADDRESS,DEFAULT_PORT); } /** * Erzeugt einen neuen Listener mit expliziter Angabe von Adresse und Port. * @param address Adresse. * @param port Port. * @throws IOException */ public MulticastClient(String address, int port) throws IOException { this.port = port; this.address = InetAddress.getByName(address); this.self = InetAddress.getLocalHost(); this.socket = new MulticastSocket(this.port); this.socket.joinGroup(this.address); this.worker = new Worker(); this.worker.start(); } /** * Stoppt den Listener. * @throws IOException */ public synchronized void stop() throws IOException { this.worker.shutdown(); } /** * Sendet Daten via Multicast. * @param data * @throws IOException */ public void send(byte[] data) throws IOException { Logger.debug("sending " + data.length + " bytes"); DatagramPacket packet = new DatagramPacket(data, data.length,this.address,this.port); socket.send(packet); } /** * Nimmt die empfangenen Daten entgegen. * Sollte ueberschrieben werden, wenn man * die Daten nutzen will. * @param packet * @throws IOException */ public void received(DatagramPacket packet) throws IOException { Logger.debug("response from " + packet.getAddress().getHostName() + ": " + new String(packet.getData())); } /** * Worker-Thread. */ private class Worker extends Thread { private Worker() { super(); setName(toString()); } /** * Beendet den Worker. * @throws IOException */ private synchronized void shutdown() throws IOException { try { this.interrupt(); socket.leaveGroup(address); } finally { socket.close(); } } /** * @see java.lang.Thread#run() */ public void run() { try { Logger.debug("start: " + toString()); while (!isInterrupted()) { byte[] buf = new byte[1024]; packet = new DatagramPacket(buf, buf.length); socket.receive(packet); InetAddress sender = packet.getAddress(); if (isOwn(sender)) continue; // sind wir selbst received(packet); } } catch (SocketException se) { if (!isInterrupted()) Logger.error("error while receiving data",se); } catch (IOException ioe) { Logger.error("error while receiving data",ioe); } finally { Logger.debug("stopped: " + toString()); } } /** * @see java.lang.Thread#toString() */ public String toString() { return "multicast-client " + address.getHostAddress() + ":" + port; } } /** * ZUm Testen. Daten koennen via Kommandozeile uebergeben werden. * @param args * @throws Exception */ public final static void main(String[] args) throws Exception { final MulticastClient client = new MulticastClient() { public void received(DatagramPacket packet) throws IOException { InetAddress sender = packet.getAddress(); InetAddress self = InetAddress.getLocalHost(); System.out.println("\n" + sender.getCanonicalHostName() + "> " + new String(packet.getData())); // Prompt wieder anzeigen System.out.print(self.getCanonicalHostName() + "> "); } }; try { System.out.println("type message and press ENTER to send."); System.out.println("press CTRL+C to exit."); InputStreamReader isr = new InputStreamReader(System.in); BufferedReader keyboard = new BufferedReader(isr); while (true) { System.out.print(client.self.getHostName() + "> "); String input = keyboard.readLine(); if (input == null || input.length() == 0) continue; client.send(input.getBytes()); } } finally { System.out.println(""); Logger.flush(); Logger.close(); client.stop(); } } /** * Prueft, ob die uebergebene IP-Adresse eine eigen ist. * @param address die zu pruefende Adresse. * @return true, wenn es die eigene ist. * @throws SocketException */ private static boolean isOwn(InetAddress address) throws SocketException { Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); while (ifaces.hasMoreElements()) { NetworkInterface i = (NetworkInterface) ifaces.nextElement(); Enumeration ips = i.getInetAddresses(); while (ips.hasMoreElements()) { if (address.equals(ips.nextElement())) return true; } } return false; } } /******************************************************************************* * $Log: MulticastClient.java,v $ * Revision 1.2 2007/11/27 18:52:56 willuhn * *** empty log message *** * * Revision 1.1 2007/08/01 17:21:40 willuhn * @N generischer Multicast-Client, mit dem man P2P Daten austauschen. In der Main-Methode befindet sich eine Beispiel-Anwendung (Chat) * * Revision 1.2 2007/06/21 09:01:49 willuhn * @N System-Presets * * Revision 1.1 2007/06/20 00:17:40 willuhn * @N Spiel-Code fuer ein RMI-Service-Discovery via TCP Multicast * ******************************************************************************/ util-V_2_8_BUILD_217/src/de/willuhn/security/000077500000000000000000000000001327231031700207255ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/security/Checksum.java000077500000000000000000000061741327231031700233450ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/security/Checksum.java,v $ * $Revision: 1.6 $ * $Date: 2011/04/27 08:38:29 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.security; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import de.willuhn.util.Base64; /** * Hilfsklasse mit statischen Methoden zur Erzeugung von Checksummen. */ public class Checksum { /** * Konstante fuer SHA1-Checksumme. */ public final static String SHA1 = "SHA1"; /** * Konstante fuer SHA-256-Checksumme. */ public final static String SHA256 = "SHA-256"; /** * Konstante fuer MD5-Checksumme. */ public final static String MD5 = "MD5"; private Checksum() { } /** * Liefert eine MD5-Checksumme der Daten im Base64-Format. * @param text * @return die Checksumme. * @throws NoSuchAlgorithmException */ public static String md5(byte[] text) throws NoSuchAlgorithmException { return Base64.encode(checksum(text,Checksum.MD5)); } /** * Liefert eine Checksumme der Daten mit dem angegebenen Algorithmus. * @param text * @param alg der Algorithmus. * @return die Checksumme. * @throws NoSuchAlgorithmException */ public static byte[] checksum(byte[] text, String alg) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance(alg); return md.digest(text); } /** * Liefert eine Checksumme der Daten. * @param data InputStream mit den Daten. * Hinweis: Die Funktion kuemmert sich NICHT um das Schliessen des Streams. * @param alg Algorithmus. * @return die Checksumme. * @see Checksum#MD5 * @see Checksum#SHA1 * @throws NoSuchAlgorithmException * @throws IOException */ public static byte[] checksum(InputStream data, String alg) throws NoSuchAlgorithmException, IOException { MessageDigest md = MessageDigest.getInstance(alg); byte[] buf = new byte[4096]; int read = 0; while ((read = data.read(buf)) != -1) md.update(buf,0,read); return md.digest(); } } /********************************************************************** * $Log: Checksum.java,v $ * Revision 1.6 2011/04/27 08:38:29 willuhn * @N SHA256 als Konstante hinzugefuegt * * Revision 1.5 2009/01/17 00:25:39 willuhn * @N Programm zum Erstellen/Verifizieren von OpenSSL-kompatiblen Signaturen mit SHA1-Digest * @N Java 1.5 compatibility * * Revision 1.4 2009/01/16 17:08:58 willuhn * @C Checksum#checksum fuehrt kein Base64-Encoding durch * * Revision 1.3 2009/01/16 16:39:56 willuhn * @N Funktion zum Erzeugen von SHA1-Checksummen * @N Funktion zum Erzeugen von Checksummen aus InputStreams * * Revision 1.2 2005/03/09 01:06:20 web0 * @D javadoc fixes * * Revision 1.1 2005/02/01 17:15:07 willuhn * *** empty log message *** * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/security/Signature.java000077500000000000000000000226741327231031700235470ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/security/Signature.java,v $ * $Revision: 1.1 $ * $Date: 2009/01/17 00:25:38 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.security; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.util.HashMap; import java.util.Map; import de.willuhn.io.IOUtil; import de.willuhn.util.Queue; /** * Hilfsklasse mit statischen Methoden zur Erzeugung und Verifizierung von Signaturen. * Die Signaturen basieren auf SHA1-Checksummen der Daten und werden mittels * Public-/Privatekey geschuetzt. * * Alternativ kann man die Signaturen auch mit den folgenden beiden OpenSSL-Befehlen * erstellen/verifizieren. Die von dieser Java-Klasse erzeugten Signaturen sind * kompatibel zu denen von OpenSSL. * *
 * openssl dgst -sha1 -sign ${privatekey-file} -out ${signature-file} < {file}
 * openssl dgst -sha1 -verify ${publickey-file} -signature ${signature-file} {file}
 * 
*/ public class Signature { /** * Der zu verwendende Algorithmus. */ private final static String ALG = "SHA1withRSA"; /** * private. */ private Signature() { } /** * Erzeugt eine Signatur fuer die uebergebenen Daten. * Die Signatur wird mit dem Algorithmus "SHA1withRSA" erstellt. * @param data die zu signierenden Daten. * @param key der Private-Key zum Signieren. * @return die Signatur. * @throws IOException wenn ein Fehler beim Lesen der Daten auftrat. * @throws GeneralSecurityException wenn ein Fehler beim Signieren auftrat. */ public static byte[] sign(InputStream data, PrivateKey key) throws GeneralSecurityException, IOException { java.security.Signature sig = java.security.Signature.getInstance(ALG); sig.initSign(key); byte[] buf = new byte[1024]; int read = 0; while ((read = data.read(buf)) != -1) { sig.update(buf,0,read); } return sig.sign(); } /** * Prueft die Signatur fuer die uebergebenen Daten. * Die Signatur wird mit dem Algorithmus "SHA1withRSA" geprueft. * @param data die zu signierenden Daten. * @param key der Public-Key zum Pruefen. * @param signature die Signatur. * @return true, wenn die Signatur ok ist. * @throws IOException wenn ein Fehler beim Lesen der Daten auftrat. * @throws GeneralSecurityException wenn ein Fehler beim Verifizieren der Signatur auftrat. */ public static boolean verifiy(InputStream data, PublicKey key, byte[] signature) throws GeneralSecurityException, IOException { java.security.Signature sig = java.security.Signature.getInstance(ALG); sig.initVerify(key); byte[] buf = new byte[1024]; int read = 0; while ((read = data.read(buf)) != -1) { sig.update(buf,0,read); } return sig.verify(signature); } /** * Main-Methode, um das Signieren und Verifzieren von der Kommandozeile aus durchfuehren zu koennen. * @param args * @throws Exception */ public final static void main(String[] args) throws Exception { if (args == null || args.length < 2) usage(); //////////////////////////////////////////////////////////////////////////// // Queue zum Abarbeiten der Parameter Queue queue = new Queue(100); for (String s:args) queue.push(s.trim()); // Das Kommando ist der erste Parameter. String command = (String) queue.pop(); if (!command.equals("sign") && !command.equals("verify")) usage(); // die restlichen pappen wir in eine Map Map options = new HashMap(); String s = null; while (queue.size() > 0) { String curr = (String) queue.pop(); if (curr == null || curr.length() == 0) continue; if (curr.startsWith("-")) { s = curr.substring(1); continue; } options.put(s,curr); } // //////////////////////////////////////////////////////////////////////////// InputStream is1 = null; InputStream is2 = null; InputStream is3 = null; OutputStream os = null; try { //////////////////////////////////////////////////////////////////////////// // 1. Load keystore String keyfile = options.get("keystore"); if (keyfile == null) error("no keystore file given"); String alias = options.get("alias"); if (alias == null) alias = "default"; String storepass = options.get("storepass"); if (storepass == null) storepass = ""; is1 = new BufferedInputStream(new FileInputStream(keyfile)); KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(is1,storepass.toCharArray()); //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // 2. Load file String file = options.get("file"); if (file == null) error("no file to sign/verify given"); is2 = new BufferedInputStream(new FileInputStream(file)); //////////////////////////////////////////////////////////////////////////// String sig = options.get("sig"); if (sig == null) sig = file + ".sha1"; if (command.equals("sign")) { //////////////////////////////////////////////////////////////////////////// // 3. a) sign String keypass = options.get("keypass"); if (keypass == null) keypass = ""; PrivateKey key = (PrivateKey) keyStore.getKey(alias,keypass.toCharArray()); if (key == null) error("key for alias \"" + alias + "\" not found"); os = new BufferedOutputStream(new FileOutputStream(sig)); os.write(Signature.sign(is2,key)); System.out.println("signature created"); //////////////////////////////////////////////////////////////////////////// } else { //////////////////////////////////////////////////////////////////////////// // 3. b) verify Certificate cert = keyStore.getCertificate(alias); if (cert == null) error("certificate for alias \"" + alias + "\" not found"); is3 = new BufferedInputStream(new FileInputStream(sig)); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int read = 0; while ((read = is3.read(buf)) != -1) bos.write(buf,0,read); boolean b = Signature.verifiy(is2,cert.getPublicKey(),bos.toByteArray()); System.out.println("verification " + (b ? "OK" : "FAILED")); System.exit(b ? 0 : 1); //////////////////////////////////////////////////////////////////////////// } } finally { IOUtil.close(is1,is2,is3,os); } } /** * Gibt eine Fehlermeldung auf STDERR aus und beendet das Programm mit dem * Return-Code 3. * @param message */ private static void error(String message) { System.err.println(message); System.exit(3); } /** * Gibt die Kommandozeilen-Optionen auf STDERR aus und beendet das Programm mit dem * Return-Code 2. */ private static void usage() { PrintStream s = System.err; s.println("usage: java -cp de_willuhn_util.jar " + Signature.class.getName() + " [sign/verify] [options]\n"); s.println(" sign : create a new signature for a file"); s.println(" verify: check the signature of a file\n"); s.println(" options:"); s.println(" -keystore path to keystore file (JKS format)"); s.println(" -storepass password of keystore file"); s.println(" -alias alias name of keystore entry (contains public and/or private key)"); s.println(" -keypass password of keystore entry (only needed for signing)"); s.println(" -file the file to sign/verify"); s.println(" -sig the signature file to create/verify"); s.println("\nexamples:\n"); s.println("java -cp de_willuhn_util.jar " + Signature.class.getName() + " sign -keystore my.keystore -storepass changeit -alias default -keypass foobar -file de_willuhn_util.jar -sig de_willuhn_util.jar.sig"); s.println("java -cp de_willuhn_util.jar " + Signature.class.getName() + " verify -keystore my.keystore -storepass changeit -alias default -keypass foobar -file de_willuhn_util.jar -sig de_willuhn_util.jar.sig"); s.println(""); s.println("hint: a JKS keystore can be created using the SUN keytool program"); s.println("\n"); System.exit(2); } } /********************************************************************** * $Log: Signature.java,v $ * Revision 1.1 2009/01/17 00:25:38 willuhn * @N Programm zum Erstellen/Verifizieren von OpenSSL-kompatiblen Signaturen mit SHA1-Digest * @N Java 1.5 compatibility * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/sql/000077500000000000000000000000001327231031700176555ustar00rootroot00000000000000util-V_2_8_BUILD_217/src/de/willuhn/sql/CheckSum.java000077500000000000000000000050351327231031700222300ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/sql/CheckSum.java,v $ * $Revision: 1.3 $ * $Date: 2009/01/16 17:08:58 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.sql; import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import de.willuhn.logging.Logger; import de.willuhn.security.Checksum; /** * Hilfsklasse zum Berechnen von Datenbank-Checksummen. */ public class CheckSum { /** * Berechnet die MD5-Checksumme einer Datenbank. * In die Berechnung fliessen alle im Schem anthaltenen Tabellen * inclusive ihrer Spaltennamen und -typen ein. * Hinweis: Die Connection wird nicht geschlossen. * @param conn Connection. * @param catalog Name des Catalogs. Kann null sein. * @param schema Name des Schemas. Kann null sein. * @return MD5-Checksumme der Datenbank. * @throws SQLException * @throws NoSuchAlgorithmException */ public static String md5(Connection conn, String catalog, String schema) throws SQLException, NoSuchAlgorithmException { Logger.info("calculating md5 checksum for database " + schema); StringBuffer sum = new StringBuffer(); ResultSet rs = null; try { DatabaseMetaData dmd = conn.getMetaData(); rs = dmd.getColumns(catalog,schema,null,null); String s = null; while (rs.next()) { s = rs.getString("TABLE_NAME") + ":" + rs.getString("COLUMN_NAME") + ":" + rs.getString("TYPE_NAME"); Logger.debug(s); sum.append(s + "\n"); } return Checksum.md5(sum.toString().getBytes()); } finally { try { if (rs != null) rs.close(); } catch (Exception e) { Logger.error("error while closing resultset",e); } } } } /********************************************************************* * $Log: CheckSum.java,v $ * Revision 1.3 2009/01/16 17:08:58 willuhn * @C Checksum#checksum fuehrt kein Base64-Encoding durch * * Revision 1.2 2009/01/16 16:39:56 willuhn * @N Funktion zum Erzeugen von SHA1-Checksummen * @N Funktion zum Erzeugen von Checksummen aus InputStreams * * Revision 1.1 2006/01/30 14:54:11 web0 * @N de.willuhn.sql * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/sql/ScriptExecutor.java000077500000000000000000000155621327231031700235170ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/sql/ScriptExecutor.java,v $ * $Revision: 1.6 $ * $Date: 2008/11/26 22:11:35 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.sql; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import de.willuhn.logging.Logger; import de.willuhn.util.ConsoleProgessMonitor; import de.willuhn.util.ProgressMonitor; /** * Util-Klasse, mit der ein SQL-Script auf einer Connection * ausgefuehrt werden kann. */ public class ScriptExecutor { /** * Main-Methode zum Starten an der Kommandozeile. * @param args Kommandozeilen-Parameter. * @throws Exception */ public static void main(String args[]) throws Exception { if (args == null || args.length != 2) die("usage: java -cp de_willuhn_util.jar [jdbc-driver] [jdbc-url] < [sql-script.sql]"); Class.forName(args[0]); Connection conn = null; try { conn = DriverManager.getConnection(args[1]); execute(new InputStreamReader(System.in),conn,new ConsoleProgessMonitor()); } finally { if (conn != null) conn.close(); } } /** * Zeigt eine Fehlermeldung an und beendet das Programm. * @param msg die Meldung. */ private static void die(String msg) { System.err.println(msg); System.exit(1); } /** * Fuehrt ein SQL-Script auf einer Datenbank-Verbindung aus. * Hinweis: Weder die Connection noch der Reader wird geschlossen. * @param reader das auszufuehrende SQL-Script. * @param conn die Connection. * @throws IOException * @throws SQLException */ public static void execute(Reader reader, Connection conn) throws IOException, SQLException { execute(reader, conn, null); } /** * Fuehrt ein SQL-Script auf einer Datenbank-Verbindung aus. * Hinweis: Weder die Connection noch der Reader wird geschlossen. * @param reader das auszufuehrende SQL-Script. * @param conn die Connection. * @param monitor ein Monitor, ueber den der Fortschritt der Ausfuehrung ausgegeben werden kann. * @throws IOException * @throws SQLException */ public static void execute(Reader reader, Connection conn, ProgressMonitor monitor) throws IOException, SQLException { Statement stmt = null; String currentStatement = null; boolean commitState = false; try { BufferedReader br = null; String thisLine = null; StringBuffer all = new StringBuffer(); int lines = 0; try { if (monitor != null) monitor.setStatusText("reading sql script"); Logger.debug("reading sql script"); br = new BufferedReader(reader); while ((thisLine = br.readLine()) != null) { if (monitor != null && lines++ % 20 == 0) monitor.addPercentComplete(1); if (!(thisLine.length() > 0)) // Zeile enthaelt nichts continue; if (thisLine.matches(" *?")) // Zeile enthaelt nur Leerzeichen continue; if (thisLine.startsWith("--")) // Kommentare continue; if (thisLine.startsWith("\n") || thisLine.startsWith("\r")) // Leerzeile continue; all.append(thisLine.trim()); } } catch (IOException e) { throw e; } finally { try { if (br != null) br.close(); } catch (Exception e) { Logger.error("error while closing file reader",e); } } String s = all.toString(); if (s == null || s.length() == 0) { Logger.info("no sql statements found in sql script"); return; } commitState = conn.getAutoCommit(); if (monitor != null) monitor.setStatusText("starting transaction"); Logger.info("starting transaction"); conn.setAutoCommit(false); stmt = conn.createStatement(); if (monitor != null) monitor.setStatusText("executing sql commands"); String[] commands = s.split(";"); double factor = 1; if (monitor != null) { factor = ((double)(100 - monitor.getPercentComplete())) / commands.length; monitor.setStatusText("executing sql commands"); } for (int i=0;i maxNumber) maxNumber = number; // Wir uebernehmen das Update nur, wenn dessen // Versionsnummer hoeher als die aktuelle ist. if (number > currentVersion) updates.add(current); } if (currentVersion > maxNumber) { // Wenn wir einen Progress-Monitor haben, dann melden wir diesen Zustand lediglich // als Fehler. Damit ueberlassen wir es dem Aufrufer, ob der das toleriert oder nicht. // Denn falls die Datenbank-Updates abwaertskompatibel waren, funktioniert die // aeltere Version ja unter Umstaenden auch problemlos auf der neueren Datenbank. Logger.error("database version too new. actual version: " + currentVersion + ", maximum expected version: " + maxNumber); ProgressMonitor monitor = this.provider.getProgressMonitor(); if (monitor != null) { monitor.setStatus(ProgressMonitor.STATUS_ERROR); monitor.setStatusText("Die Datenbank wurde bereits mit einer neueren Programmversion geöffnet"); return; } throw new ApplicationException("Die Datenbank wurde bereits mit einer neueren Programmversion geöffnet"); } // Keine Updates gefunden if (updates.size() == 0) { Logger.info("no new updates found"); return; } // Wir fuehren die Updates aus. Logger.info("found " + updates.size() + " update files"); Logger.info("encoding: " + this.encoding); for (int i=0;i= 9 * (dort existiert "sun.misc.BASE64*" nicht mehr). */ public class Base64 { private static Encoder encoder = null; static { for (Encoder e:Arrays.asList(new JavaEncoder(),new SunEncoder())) { if (e.exists()) { encoder = e; Logger.info("using base64 encoder/decoder: " + encoder.getClass().getSimpleName()); break; } } if (encoder == null) Logger.warn("no base64 encoder/decoder found"); } /** * Dekodiert Base64 in Text. * @param base64 Base64. * @return Text. * @throws IOException */ public final static byte[] decode(String base64) throws IOException { if (encoder == null) throw new IOException("base64 decoder not available"); return encoder.decode(base64); } /** * Kodiert Text nach Base64. * @param text * @return Base64-Version. */ public final static String encode(byte[] text) { if (encoder == null) return null; return encoder.encode(text); } /** * Interface, welches die getrennten Implementierungen kapselt. */ private static interface Encoder { /** * Liefert true, wenn der Encoder existiert. * @return true, wenn der Encoder existiert. */ boolean exists(); /** * Dekodiert Base64 in Text. * @param base64 Base64. * @return Text. * @throws IOException */ public byte[] decode(String base64) throws IOException; /** * Kodiert Text nach Base64. * @param text * @return Base64-Version. */ public String encode(byte[] text); } /** * Implementierung eines Encoders mit der SUN-Implementierung. */ private static class SunEncoder implements Encoder { private final static String DECODER = "sun.misc.BASE64Decoder"; private final static String ENCODER = "sun.misc.BASE64Encoder"; private Object decoder = null; private Object encoder = null; private Method decode = null; private Method encode = null; /** * ct. */ private SunEncoder() { this.decoder = load(DECODER); this.encoder = load(ENCODER); } /** * Laedt die Klasse und erzeugt eine Instanz. * @param className der Name der Klasse. * @return die Instanz oder NULL, wenn die Klasse nicht geladen/instanziiert werden konnte. */ private static Object load(final String className) { try { return Class.forName(className).newInstance(); } catch (Throwable t) { Logger.debug("base64 encoder/decoder " + className + " not available on this java version"); return null; } } /** * @see de.willuhn.util.Base64.Encoder#exists() */ public boolean exists() { return decoder != null && encoder != null; } /** * @see de.willuhn.util.Base64.Encoder#decode(java.lang.String) */ public byte[] decode(String base64) throws IOException { if (this.decoder == null) throw new IOException("base64 decoder not available"); try { if (this.decode == null) this.decode = this.decoder.getClass().getMethod("decodeBuffer",new Class[]{String.class}); return (byte[]) this.decode.invoke(this.decoder,base64); } catch (Throwable t) { if (t instanceof IOException) throw (IOException) t; throw new IOException(t); } } /** * @see de.willuhn.util.Base64.Encoder#encode(byte[]) */ public String encode(byte[] text) { if (this.encoder == null) { Logger.warn("base64 encoder not available"); return null; } try { if (this.encode == null) this.encode = this.encoder.getClass().getMethod("encode",new Class[]{byte[].class}); return (String) this.encode.invoke(this.encoder,text); } catch (Throwable t) { Logger.error("unable to encode base64",t); return null; } } } /** * Implementierung eines Encoders mit der Java-Implementierung (ab Java 1.8 verfuegbar). */ private static class JavaEncoder implements Encoder { private final static String BASE64 = "java.util.Base64"; private Object decoder = null; private Object encoder = null; private Method decode = null; private Method encode = null; /** * ct. */ private JavaEncoder() { this.decoder = load(BASE64,"getMimeDecoder"); this.encoder = load(BASE64,"getMimeEncoder"); } /** * Laedt den Encoder. * @param className der Name der Klasse. * @return die Instanz oder NULL, wenn die Klasse nicht geladen/instanziiert werden konnte. */ private static Object load(final String className, final String method) { try { Class base64 = Class.forName(className); Method m = base64.getMethod(method); return m.invoke(base64); } catch (Throwable t) { Logger.debug("base64 encoder/decoder " + className + " not available on this java version"); return null; } } /** * @see de.willuhn.util.Base64.Encoder#exists() */ public boolean exists() { return decoder != null && encoder != null; } /** * @see de.willuhn.util.Base64.Encoder#decode(java.lang.String) */ public byte[] decode(String base64) throws IOException { if (this.decoder == null) throw new IOException("base64 decoder not available"); try { if (this.decode == null) this.decode = this.decoder.getClass().getMethod("decode",new Class[]{String.class}); return (byte[]) this.decode.invoke(this.decoder,base64); } catch (Throwable t) { if (t instanceof IOException) throw (IOException) t; throw new IOException(t); } } /** * @see de.willuhn.util.Base64.Encoder#encode(byte[]) */ public String encode(byte[] text) { if (this.encoder == null) { Logger.warn("base64 encoder not available"); return null; } try { if (this.encode == null) this.encode = this.encoder.getClass().getMethod("encodeToString",new Class[]{byte[].class}); return (String) this.encode.invoke(this.encoder,text); } catch (Throwable t) { Logger.error("unable to encode base64",t); return null; } } } } util-V_2_8_BUILD_217/src/de/willuhn/util/ClassFinder.java000077500000000000000000000123761327231031700231070ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/ClassFinder.java,v $ * $Revision: 1.8 $ * $Date: 2008/06/24 13:47:04 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Hashtable; import de.willuhn.logging.Logger; /** */ /** * Klassen-Sucher. * Diese Teil hier kann man mit Klassen fuettern und danach in verschiedener Hinsicht befragen. */ public class ClassFinder { private Hashtable cache = new Hashtable(); private ArrayList classes = new ArrayList(); private ArrayList children = new ArrayList(); /** * ct. */ ClassFinder() { } /** * Fuegt einen Child-Finder hinzu. * @param finder */ void addFinder(ClassFinder finder) { this.children.add(finder); } /** * Fuegt die Klasse dem Finder hinzu. * @param clazz die Klasse. */ void addClass(Class clazz) { if (isImpl(clazz)) classes.add(clazz); } /** * Sucht nach ggf vorhandenen Klassen, die das uebergebene Interface implementieren. * Hinweis: Die Funktion liefert generell nur instanziierbare Klassen. * Es werden also weder abstrakte Klassen, noch Interfaces oder RMI-Stubs geliefert. * @param interphase das Interface. * Handelt es sich hierbei nicht um ein Interface sondern eine instanziierbare * nicht abstrakte Klasse, wir diese direkt und ohne Suche wieder zurueckgegeben. * @return die gefundenen Klassen. * @throws ClassNotFoundException wenn der Implementor nichts gefunden hat. */ public Class[] findImplementors(Class interphase) throws ClassNotFoundException { // erstmal im Cache checken Class[] found = (Class[]) cache.get(interphase); if (found != null && found.length > 0) return found; // Wenn es eine Implementierung ist, liefern // wir sie direkt zurueck if (isImpl(interphase)) return new Class[] {interphase}; long start = System.currentTimeMillis(); // So, jetzt geht die Suche los // Ggf. muessen wir die Ableitungshierachie hochwandern. // Wenn mehrere Klassen das Interface implementieren, sammeln // wir diese in einer Ranking-Liste. ArrayList ranking = new ArrayList(); // Wir suchen in den Child-Findern for (int i=0;i 0) ranking.addAll(Arrays.asList(found)); } catch (ClassNotFoundException e) { // Wenn die Kinder nichts gefunden haben, machen wir weiter } } // Jetzt suchen wir lokal Class test = null; // Hier speichern wir alle direkten Treffer um bei der // Suche in der Ableitungs-Hierachie keine Duplikate // zu finden. Hashtable duplicates = new Hashtable(); // ueber alle Klassen iterieren for (int i=0;i colorCache = new ArrayList(); /** * Konstante, um mit den Eclipse-Farben zu beginnen. */ public final static int PALETTE_ECLIPSE = 0; /** * Konstante, um mit den Pastel-Farben zu beginnen. */ public final static int PALETTE_PASTEL = 8; /** * Konstante, um mit den satten Farben zu beginnen. */ public final static int PALETTE_RICH = 16; /** * Konstante, um mit den Office-Farben zu beginnen. */ public final static int PALETTE_OFFICE = 24; // Basis-Palette static { // Eclipse-Farben colorCache.add(new int[]{225,225,255}); // hellblau colorCache.add(new int[]{223,197, 41}); // ocker colorCache.add(new int[]{249,225,191}); // blass orange colorCache.add(new int[]{255,205,225}); // rosa colorCache.add(new int[]{225,255,225}); // hellgruen colorCache.add(new int[]{255,191,255}); // rosa 2 colorCache.add(new int[]{185,185,221}); // graublau colorCache.add(new int[]{ 40,255,148}); // gruen // Pastel-Farben colorCache.add(new int[]{255,161,161}); // hellrot colorCache.add(new int[]{255,215,161}); // orange colorCache.add(new int[]{250,255,161}); // gelb colorCache.add(new int[]{197,255,161}); // gruen colorCache.add(new int[]{161,255,253}); // tuerkis colorCache.add(new int[]{161,192,255}); // blau colorCache.add(new int[]{161,255,213}); // gruen 2 colorCache.add(new int[]{243,161,255}); // rosa // Satte Farben colorCache.add(new int[]{238, 85, 27}); // rot colorCache.add(new int[]{ 81,180, 51}); // gruen colorCache.add(new int[]{ 5,141,199}); // blau colorCache.add(new int[]{ 25, 76,126}); // marine colorCache.add(new int[]{255,127, 15}); // orange colorCache.add(new int[]{153,107, 19}); // braun colorCache.add(new int[]{153, 41, 95}); // violett colorCache.add(new int[]{226,226, 54}); // sandgelb // Office-Farben colorCache.add(new int[]{ 0, 87,150}); colorCache.add(new int[]{255, 83, 23}); colorCache.add(new int[]{255,218, 46}); colorCache.add(new int[]{105,171, 41}); colorCache.add(new int[]{142, 0, 47}); colorCache.add(new int[]{147,210,255}); colorCache.add(new int[]{ 65, 81, 8}); colorCache.add(new int[]{186,215, 0}); colorCache.add(new int[]{ 93, 45,128}); colorCache.add(new int[]{255,164, 23}); colorCache.add(new int[]{206, 0, 19}); colorCache.add(new int[]{ 0,148,216}); } /** * Erzeugt die RGB-Werte fuer eine Farbe. * @param pos Offset. * Bei einem Wert zwischen 0 und 35 wird immer die gleiche Farbe aus einer * vordefinierten Palette geliefert. Bei hoeheren Werten wird eine zufaellig * ausgewuerfelt, die bei jedem Aufruf einen anderen Wert hat. * Warum nicht zwei Funktionen - eine fuer die statische Palette * und eine fuer Zufalls-Farben? Weil man solche Farbwerte typischerweise * zum Zeichnen von Charts (z.Bsp. Kreis- oder Linien-Diagrammen) braucht. * Dort hat man eine Liste von Messreihen, die in einer Schleife dem * Chart zugeordnet werden. Man kann also einfach den Schleifencounter * (meist "int i") einfach uebergeben. Fuer die ersten 36 Zahlenreihen * kriegt man feste Farbcodes - fuer alles darueber Zufallsfarben. * Da man meist nicht mehr als 36 Zahlenreihen hat, reicht der statische * Pool fuer gewoehnlich aus. * @return RGB-Werte. */ public static int[] create(int pos) { int[] color = null; // Haben wir hier schon eine Farbe im Cache? if (colorCache.size() > pos) return colorCache.get(pos); Random rand = new Random(); int brightness = 40; color = new int[]{ 255 - brightness - rand.nextInt(30), 255 - brightness - rand.nextInt(30), 255 - brightness - rand.nextInt(30) }; // Farbrichtung rotieren // Stellt sicher, dass kein Grau rauskommt, sondern eine // Farbe dominiert color[pos % 3] = 255; // Wir fuegen die Farbe zum Cache hinzu, damit die Farbe // wenigstens innerhalb der JVM-Session konstant bleibt try { colorCache.add(pos,color); } catch (IndexOutOfBoundsException e) { // pueh } return color; } /** * Main-Methode, falls man den mal von der Konsole aus nutzen will. * @param args * @throws Exception */ public final static void main(String[] args) throws Exception { for (int i=100;i<1000;++i) { int[] values = ColorGenerator.create(i); System.out.println(i + ": " + Arrays.toString(values)); } } } /********************************************************************** * $Log: ColorGenerator.java,v $ * Revision 1.4 2010/05/19 14:47:38 willuhn * @N Ausfall von STDOUT tolerieren * * Revision 1.3 2009/11/02 17:43:06 willuhn * *** empty log message *** * * Revision 1.2 2009/08/24 23:47:41 willuhn * @N Farbkreis erweitert * * Revision 1.1 2009/08/21 22:56:04 willuhn * @N Farb-Generator fuer die Erzeugung von Farbwerten aus einem Pool oder notfalls Zufallsfarben * **********************************************************************/ util-V_2_8_BUILD_217/src/de/willuhn/util/ConsoleProgessMonitor.java000066400000000000000000000034301327231031700252130ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/ConsoleProgessMonitor.java,v $ * $Revision: 1.1 $ * $Date: 2008/11/26 22:11:35 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn software & services * All rights reserved * **********************************************************************/ package de.willuhn.util; /** * Dummy-Implementierung eines Progress-Monitors, der nach STDOUT schreibt. */ public class ConsoleProgessMonitor implements ProgressMonitor { private int percent = 0; /** * @see de.willuhn.util.ProgressMonitor#addPercentComplete(int) */ public void addPercentComplete(int percent) { this.percent += percent; } /** * @see de.willuhn.util.ProgressMonitor#getPercentComplete() */ public int getPercentComplete() { return this.percent; } /** * @see de.willuhn.util.ProgressMonitor#log(java.lang.String) */ public void log(String msg) { System.out.println(msg); } /** * @see de.willuhn.util.ProgressMonitor#setPercentComplete(int) */ public void setPercentComplete(int percent) { this.percent = percent; } /** * @see de.willuhn.util.ProgressMonitor#setStatus(int) */ public void setStatus(int status) { } /** * @see de.willuhn.util.ProgressMonitor#setStatusText(java.lang.String) */ public void setStatusText(String text) { System.out.println(text); } } /********************************************************************** * $Log: ConsoleProgessMonitor.java,v $ * Revision 1.1 2008/11/26 22:11:35 willuhn * @N Console-Progressmonitor * @N main()-Funktion fuer ScriptExecutor * **********************************************************************/ util-V_2_8_BUILD_217/src/de/willuhn/util/History.java000077500000000000000000000021531327231031700223430ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/History.java,v $ * $Revision: 1.1 $ * $Date: 2004/01/08 21:38:39 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; /** * Bildet eine History ab, die immer eine definierte Anzahl der letzten * Elemente enthaelt. */ public class History extends Queue { /** * ct. * @param capacity */ public History(int capacity) { super(capacity); } /** * @see de.willuhn.util.Queue#push(java.lang.Object) */ public synchronized void push(Object o) { if (full()) pop(); try { super.push(o); } catch (QueueFullException e){} } } /********************************************************************** * $Log: History.java,v $ * Revision 1.1 2004/01/08 21:38:39 willuhn * *** empty log message *** * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/util/I18N.java000077500000000000000000000161001327231031700213560ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/I18N.java,v $ * $Revision: 1.14 $ * $Date: 2010/11/01 13:26:08 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import de.willuhn.logging.*; /** * Diese Klasse behandelt die Internationalisierung. * Sie uebersetzt nicht nur alle Strings sondern speichert auch alle * nicht uebersetzbaren Strings waehrend der aktuellen Sitzung und * speichert diese beim Beenden der Anwendung im Temp-Verzeichnis ab. * @author willuhn */ public class I18N { private ResourceBundle bundle; private Properties fallbackBundle; private Properties unresolved = new Properties(); private Locale locale; private final static String DEFAULTPATH = "lang/messages"; /** * ct. * Verwendet das Default-Locale und "lang/messages" als Resource-Path. */ public I18N() { this(null,null,null); } /** * ct. * Verwendet das uebergebene Locale und "lang/messages" als Resource-Path. * @param l Locale. */ public I18N(Locale l) { this(null,l,null); } /** * ct. * Verwendet den uebergebenen Resource-Path und das Default-Locale. * @param resourcePath */ public I18N(String resourcePath) { this(resourcePath,null,null); } /** * Initialisiert diese Klasse mit dem angegebenen Locale. * @param resourcePath * @param l das zu verwendende Locale. */ public I18N(String resourcePath, Locale l) { this(resourcePath,l,null); } /** * Initialisiert diese Klasse mit dem angegebenen Locale. * @param resourcePath * @param l das zu verwendende Locale. * @param loader der Classloader. */ public I18N(String resourcePath, Locale l, ClassLoader loader) { if (resourcePath == null) resourcePath = DEFAULTPATH; if (l == null) this.locale = Locale.getDefault(); else this.locale = l; Logger.info("loading resource bundle " + resourcePath + " for locale " + (l == null ? "" : l.toString())); if (l == null || resourcePath == null) return; if (loader != null) bundle = ResourceBundle.getBundle(resourcePath,l,loader); else bundle = ResourceBundle.getBundle(resourcePath,l); } /** * ct. * Verwendet den Inputstream zu Lesen der Resourcen. * @param is */ public I18N(InputStream is) { fallbackBundle = new Properties(); if (is == null) Logger.error("no inputstream given for I18N"); try { fallbackBundle.load(is); } catch (IOException e) { Logger.error("error while reading resource bundle from inputstream",e); } } /** * Uebersetzt den angegebenen String und liefert die uebersetzte * Version zurueck. Kann der String nicht uebersetzt werden, wird * der Original-String zurueckgegeben. * @param key zu uebersetzender String. * @return uebersetzter String. */ public String tr(String key) { String translated = null; try { if (bundle != null) translated = bundle.getString(key); else if (fallbackBundle != null) translated = fallbackBundle.getProperty(key); } catch(MissingResourceException e) { } if (translated != null) return translated; unresolved.put(key,key); return key; } /** * Uebersetzt den angegebenen String und liefert die uebersetzte * Version zurueck. Kann der String nicht uebersetzt werden, wird * der Original-String zurueckgegeben. *
Hinweis:. Die Textmarken fuer die Ersetzungen sind mit {n} zu definieren * wobei n von 0 beginnend hochgezaehlt wird und genauso oft vorkommen darf wie das String-Array * Elemente besitzt.
* Bsp: i18n.tr("Das ist eine {0} nuetzliche {1}", "besonders","Funktion"); * @param key zu uebersetzender String. * @param replacements String-Array mit den einzusetzenden Werten. * @return uebersetzter String. */ public String tr(String key, String... replacements) { return MessageFormat.format(tr(key),(Object[])replacements); } /** * Uebersetzt den angegeben String und liefert die uebersetzte Version zurueck. * Diese Funktion existiert der Einfachheit halber fuer Strings, welche lediglich * ein Replacement besitzen. Die sonst notwendige Erzeugung eines String-Arrays * mit nur einem Element entfaellt damit.
* Bsp: i18n.tr("Das ist eine nuetzliche {0}", "Funktion"); * @param key zu uebersetzender String. * @param replacement String mit dem einzusetzenden Wert. * @return uebersetzter String. */ public String tr(String key, String replacement) { return tr(key,new String[]{replacement}); } /** * Schreibt alle bis dato nicht uebersetzbaren Strings in den angegebenen OutputStream. * @param os Stream, in den geschrieben werden soll. * @throws IOException */ public void storeUntranslated(OutputStream os) throws IOException { Logger.info("saving unresolved locale strings"); unresolved.store(os, "unresolved strings for locale " + locale.toString()); } } /********************************************************************* * $Log: I18N.java,v $ * Revision 1.14 2010/11/01 13:26:08 willuhn * @N Support fuer varargs in tr * * Revision 1.13 2008/05/19 22:29:49 willuhn * @B NPE * * Revision 1.12 2008/05/19 22:25:55 willuhn * @B NPE * * Revision 1.11 2008/05/19 22:19:54 willuhn * @R UNDO: Fuehrt dazu, dass nicht mehr erkannt werden kann, ob ein Resource-Bundle ueberhaupt existiert. * * Revision 1.9 2007/03/26 23:58:19 willuhn * @C compiler warnings * * Revision 1.8 2004/11/12 18:18:19 willuhn * @C Logging refactoring * * Revision 1.7 2004/11/12 16:19:33 willuhn * *** empty log message *** * * Revision 1.6 2004/11/05 19:42:03 willuhn * *** empty log message *** * * Revision 1.5 2004/11/05 01:50:58 willuhn * *** empty log message *** * * Revision 1.4 2004/06/10 20:57:34 willuhn * @D javadoc comments fixed * * Revision 1.3 2004/04/01 22:07:16 willuhn * *** empty log message *** * * Revision 1.2 2004/03/03 22:27:33 willuhn * @N added Lock * * Revision 1.1 2004/01/08 21:38:39 willuhn * *** empty log message *** * * Revision 1.6 2004/01/06 20:11:21 willuhn * *** empty log message *** * * Revision 1.5 2003/12/10 00:47:12 willuhn * @N SearchDialog done * @N ErrorView * * Revision 1.4 2003/11/30 16:23:09 willuhn * *** empty log message *** * * Revision 1.3 2003/11/21 02:10:21 willuhn * @N prepared Statements in AbstractDBObject * @N a lot of new SWT parts * * Revision 1.2 2003/11/13 00:37:35 willuhn * *** empty log message *** * * Revision 1.1 2003/10/23 21:49:46 willuhn * initial checkin * **********************************************************************/ util-V_2_8_BUILD_217/src/de/willuhn/util/JarInfo.java000077500000000000000000000071241327231031700222350ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/JarInfo.java,v $ * $Revision: 1.7 $ * $Date: 2005/07/14 20:28:57 $ * $Author: web0 $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.io.IOException; import java.util.jar.JarFile; import java.util.jar.Manifest; /** * Hilfs-Klasse, um Meta-Informationen aus JARs zu lesen. * Dabei werden die INFOs aus dem Manifest verwendet. */ public class JarInfo { private Manifest manifest = null; /** * Attribut des Typs Version. */ public final static String ATTRIBUTE_VERSION = "Implementation-Version"; /** * Attribut des Typs Title. */ public final static String ATTRIBUTE_TITLE = "Implementation-Title"; /** * Attribut des Typs Buildnumber. */ public final static String ATTRIBUTE_BUILDNUMBER = "Implementation-Buildnumber"; /** * Attribut des Typs Built-Date. */ public final static String ATTRIBUTE_BUILDDATE = "Built-Date"; /** * ct. * @param jar das Jar-File, aus dem die Infos gelesen werden sollen. * @throws IOException */ public JarInfo(JarFile jar) throws IOException { this.manifest = jar.getManifest(); } /** * Liefert den Wert des genannten Attributes. * @param name Name des Attributes. * @return Wert des Attributes. */ public String getAttribute(String name) { return manifest.getMainAttributes().getValue(name); } /** * Liefert die Versionsnummer des JARs, die im Manifest als Attribut "Implementation-Version" hinterlegt ist. * Wenn der String das Format <Major-Number>.<Minor-Number> hat, wird die Version als Double zurueckgeliefert. * Existiert das Attribut nicht oder kann es nicht geparst werden, wird 1.0 zurueckgeliefert. * @return Version des Plugins. */ public double getVersion() { try { return Double.parseDouble(getAttribute(ATTRIBUTE_VERSION)); } catch (Exception e) { return 1.0; } } /** * Liefert die Build-Nummer des JARs, die im Manifest als Attribut "Implementation-Buildnumber" hinterlegt ist. * Existiert das Attribut nicht oder kann es nicht geparst werden, wird 1 zurueckgeliefert. * @return Buildnumber des Plugins. */ public int getBuildnumber() { try { return Integer.parseInt(getAttribute(ATTRIBUTE_BUILDNUMBER)); } catch (Exception e) { return 1; } } /** * Liefert das Build-Dartum des JARs, das im Manifest als Attribut "Built-Date" hinterlegt ist. * Existiert das Attribut nicht oder kann es nicht geparst werden, wird null zurueckgeliefert. * @return Buildnumber des Plugins. */ public String getBuildDate() { try { return getAttribute(ATTRIBUTE_BUILDDATE); } catch (Exception e) { } return null; } } /********************************************************************** * $Log: JarInfo.java,v $ * Revision 1.7 2005/07/14 20:28:57 web0 * *** empty log message *** * * Revision 1.6 2005/07/14 17:56:53 web0 * @N JarInfo wieder hinzugefuegt * * Revision 1.4 2004/06/10 20:57:34 willuhn * @D javadoc comments fixed * * Revision 1.3 2004/05/25 23:24:03 willuhn * *** empty log message *** * * Revision 1.2 2004/04/14 21:56:39 willuhn * *** empty log message *** * * Revision 1.1 2004/04/14 21:48:34 willuhn * *** empty log message *** * **********************************************************************/ util-V_2_8_BUILD_217/src/de/willuhn/util/JarLoader.java000066400000000000000000000050351327231031700225440ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/JarLoader.java,v $ * $Revision: 1.2 $ * $Date: 2010/09/29 10:47:39 $ * $Author: willuhn $ * * Copyright (c) by willuhn - software & services * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import de.willuhn.io.FileFinder; import de.willuhn.logging.Logger; /** * Util-Klasse, mit einzelne Jar-Dateien oder ganze Verzeichnisse * von Jar-Dateien zur Laufzeit in den Classppath geladen werden koennen. */ public class JarLoader { /** * Laedt die Jars rekursive im angegebenen Verzeichnis. * @param dir das Verzeichnis, in dem sich die Jars befinden. * @throws IOException wenn die Jars nicht geladen werden koennen. */ public static void loadJars(File dir) throws IOException { if (!dir.exists() || !dir.isDirectory() || !dir.canRead()) throw new IOException("unable to read dir " + dir); FileFinder finder = new FileFinder(dir); finder.extension(".jar"); File[] jars = finder.findRecursive(); for (File jar:jars) loadJar(jar); } /** * Laedt ein einzelnes Jar. * @param jar die zu ladende Jar-Datei. * @throws IOException wenn das Jar nicht geladen werden kann. */ public static void loadJar(File jar) throws IOException { if (!jar.isFile() || !jar.canRead()) throw new IOException("unable to read file " + jar); try { URLClassLoader loader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); method.setAccessible(true); Logger.debug("loading " + jar); method.invoke(loader, new Object[]{jar.toURI().toURL()}); } catch (IOException ioe) { throw ioe; } catch (Exception e) { throw new IOException("unable to load jar " + jar + ": " + e.getMessage()); } } } /********************************************************************** * $Log: JarLoader.java,v $ * Revision 1.2 2010/09/29 10:47:39 willuhn * @B den Konstruktor gibts erst in Java 1.6 * * Revision 1.1 2010-09-29 10:44:35 willuhn * @N Ein Jar-Loader und ein Platform-Util * * Revision 1.1 2010/09/28 16:40:38 willuhn * @N initial checkin * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/util/MultipleClassLoader.java000077500000000000000000000235171327231031700246210ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/MultipleClassLoader.java,v $ * $Revision: 1.35 $ * $Date: 2011/07/18 15:43:35 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import de.willuhn.io.FileFinder; import de.willuhn.logging.Logger; /** * ClassLoader der sich beliebiger anderer ClassLoader bedient. */ public class MultipleClassLoader extends ClassLoader { private String name = null; private ArrayList loaders = new ArrayList(); private Hashtable cache = new Hashtable(); private ClassFinder finder = new ClassFinder(); private URLLoader ucl = new URLLoader(); /** * Erzeugt eine neue Instanz des Classloaders. */ public MultipleClassLoader() { super(); } /** * Vergibt einen Namen fuer den Classloader. * @param name Name fuer den Classloader. */ public void setName(String name) { this.name = name; } /** * Liefert den Namen des Classloaders. * @return der Name des Classloaders. */ public String getName() { if (this.name == null) return "multipleClassLoader"; return this.name; } /** * Fuegt einen weiteren ClassLoader hinzu, * @param loader der hinzuzufuegende Classloader. */ public void addClassloader(ClassLoader loader) { if (loader == null) return; Logger.debug(this.getName() + ": adding class loader " + loader.getClass().getName()); loaders.add(loader); if (loader instanceof MultipleClassLoader) { finder.addFinder(((MultipleClassLoader) loader).getClassFinder()); } } /** * Fuegt die uebergebene URL dem Class-Loader hinzu. * @param url die URL. */ public void add(URL url) { this.ucl.addURL(url); } /** * Liefert eine Liste aller URLs, die im Classloader registriert sind. * Diese Liste enthaelt sowohl lokale Ressourcen als auch remote Ressourcen. * @return Liste aller URLs. */ public URL[] getURLs() { return this.ucl.getURLs(); } /** * Liefert eine Liste aller lokalen Ressourcen. Also getURLs() abzueglich remote Ressourcen. * @return Liste der lokalen Files/Jars. */ public File[] getFiles() { ArrayList l = new ArrayList(); URL[] urls = getURLs(); for (int i=0;i getResources(String name) throws IOException { Enumeration urls = ucl.getResources(name); if (urls != null && urls.hasMoreElements()) return urls; return super.getResources(name); } /** * @see java.lang.ClassLoader#findClass(java.lang.String) */ protected Class findClass(String name) throws ClassNotFoundException { return load(name); } /** * @see java.lang.ClassLoader#loadClass(java.lang.String) */ public Class loadClass(String name) throws ClassNotFoundException { return load(name); } /** * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean) */ protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c = load(name); if (resolve) resolveClass(c); return c; } /** * Laedt die angegebene Klasse und initialisiert sie. * @param className Name der Klasse. * @return Die Klasse. * @throws ClassNotFoundException * @throws LinkageError Das sind NoClassDefFoundError und Co. */ public Class load(String className) throws ClassNotFoundException, LinkageError { // zuerst im Cache schauen. Class c = (Class) cache.get(className); if (c != null) return c; LinkageError error = null; try { // Dann versuchen wir es mit 'nem URLClassLoader, der alle URLs kennt. // Wir nehmen deswegen nur einen URLClassloader, damit sichergestellt // ist, dass dieser eine alle Plugins und deren Jars kennt. // URLClassLoader checken // Da wir dem UCL als Parent-Classloader nicht uns selbst sondern // den System-Classloader uebergeben haben, brauchen wir nur // den UCL fragen und nicht extra nochmal den System-Classloader return findVia(ucl,className); } catch (LinkageError r) { error = r; } catch (ClassNotFoundException e) { // kann passieren - wir suchen im naechsten Classloader } // ok, wir fragen die anderen ClassLoader ClassLoader l = null; for (int i=0;i STATUS_MAP = new HashMap() {{ put(STATUS_CANCEL, "CANCEL"); put(STATUS_DONE, "DONE"); put(STATUS_ERROR, "ERROR"); put(STATUS_NONE, "NONE"); put(STATUS_RUNNING,"RUNNING"); }}; /** * Teilt dem Monitor mit, wieviel Prozent der Aufgabe bereits abgearbeitet sind. * Bitte einen absoluten Wert angeben. Der Fortschritt wird dann unabhaengig * vom vorherigen Wert auf den hier uebergebenen gesetzt. * @param percent prozentualer Fortschritt (muss zwischen 0 und 100 liegen). */ public void setPercentComplete(int percent); /** * Teilt dem Monitor mit, wieviel Prozent der Aufgabe gerade erledigt wurde. * Bitte hier einen relativen positiven Wert angeben, um den der aktuelle * Wert erhoeht werden soll. * @param percent Anzahl der Prozent-Punkte, um die der Fortschritt erhoeht werden soll. */ public void addPercentComplete(int percent); /** * Liefert den aktuell angezeigten Fortschritt in Prozent. * @return aktueller Fortschritt. */ public int getPercentComplete(); /** * Teilt dem Monitor den aktuellen Status mit. * @param status der aktuelle Status. * @see ProgressMonitor#STATUS_NONE * @see ProgressMonitor#STATUS_RUNNING * @see ProgressMonitor#STATUS_DONE * @see ProgressMonitor#STATUS_CANCEL * @see ProgressMonitor#STATUS_ERROR */ public void setStatus(int status); /** * Teilt dem Monitor einen sprechenden Status-Text mit. * @param text Status-Text. */ public void setStatusText(String text); /** * Teilt dem Monitor mit, dass der angegebene Text protokolliert werden soll. * @param msg die zur protokollierende Nachricht. */ public void log(String msg); } /********************************************************************** * $Log: ProgressMonitor.java,v $ * Revision 1.4 2005/07/07 22:15:40 web0 * *** empty log message *** * * Revision 1.3 2004/11/04 22:41:46 willuhn * *** empty log message *** * * Revision 1.2 2004/11/04 17:48:31 willuhn * *** empty log message *** * * Revision 1.1 2004/10/07 18:06:10 willuhn * @N ZipExtractor * * Revision 1.1 2004/08/11 00:39:25 willuhn * *** empty log message *** * * Revision 1.1 2004/08/09 22:24:16 willuhn * *** empty log message *** * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/util/Queue.java000077500000000000000000000070251327231031700217710ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/Queue.java,v $ * $Revision: 1.5 $ * $Date: 2006/10/10 17:31:03 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.util.Arrays; import java.util.List; import java.util.Vector; /** * Bildet eine Queue nach FIFO-Prinzip ab (First in, First out). * Die Queue enthaelt eine definierte Anzahl von Elementen. Diese werden * in der Reihenfolge abgearbeitet, wie sie hinzugefuegt wurden. * Sie ist synchronized. */ public class Queue { private int capacity = 10; private Vector v = null; /** * Die Minimal-Kapazitaet der Queue. */ public static int CAPACITY_MIN = 2; /** * Die Maximal-Kapazitaet der Queue. */ public static int CAPACITY_MAX = 1000; /** * ct. * @param capacity maximale Kapazitaet, die die Queue haben soll. */ public Queue(int capacity) { if (capacity >= CAPACITY_MIN && capacity <= CAPACITY_MAX) this.capacity = capacity; v = new Vector(this.capacity); } /** * Entfernt das naechste zu bearbeitende Objekt aus der Queue und liefert es zurueck. * @return naechstes zu bearbeitendes Objekt. */ public synchronized Object pop() { Object o = v.get(0); v.removeElementAt(0); return o; } /** * Liefert die aktuelle Groesse der Queue. * @return aktuelle Groesse der Queue. */ public int size() { return v.size(); } /** * Liefert eine Liste aller Elemente der Queue. * Es wird nur eine Kopie ausgegeben. * @return Liste aller Elemente. */ public synchronized List elements() { return Arrays.asList(v.toArray()); } /** * Liefert ein Object-Array mit allen momentan in der Queue befindlichen Objekten. * @param type Objekt-Typ, der fuer das Array verwendet werden soll. * @return Array mit Objects. */ public Object[] toArray(Object[] type) { return v.toArray(type); } /** * Prueft, ob die Queue voll ist. * @return true, wenn sie voll ist. */ public boolean full() { return (v.size() >= capacity); } /** * Fuegt der Queue ein weiteres Objekt hinzu. Ist die Queue voll, wird eine * Exception geworfen * @param o das hinzuzufuegende Objekt. * @throws QueueFullException Wenn die Queue voll ist. */ public synchronized void push(Object o) throws QueueFullException { if (full()) throw new QueueFullException("maximum queue size reached"); v.addElement(o); } /** * Wird geworfen, wenn die Queue voll ist und trotzdem versucht wird, Daten * hineinzuschreiben. */ public static class QueueFullException extends Exception { /** * Erzeugt eine neue Exception dieses Typs mit der genannten Meldung. * @param message anzuzeigende Meldung. */ public QueueFullException(String message) { super(message); } } } /********************************************************************** * $Log: Queue.java,v $ * Revision 1.5 2006/10/10 17:31:03 willuhn * @R removed ArrayEnumeration - totally useless ;) * * Revision 1.4 2004/03/06 18:24:47 willuhn * @D javadoc * * Revision 1.3 2004/01/06 19:58:29 willuhn * @N ArrayEnumeration * * Revision 1.2 2004/01/05 23:08:04 willuhn * *** empty log message *** * * Revision 1.1 2004/01/05 21:46:29 willuhn * @N added queue * @N logger writes now in separate thread * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/util/Session.java000077500000000000000000000213221327231031700223240ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/Session.java,v $ * $Revision: 1.13 $ * $Date: 2009/11/24 10:48:18 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Observable; import de.willuhn.logging.Logger; /** * Implementierung eines Session-Containers. * @author willuhn */ public class Session extends Observable { private static Worker worker = null; /** * Liefert den Worker-Thread und erstellt ggf einen neuen. * @return der Worker-Thread. */ private final static synchronized Worker getWorker() { if (worker != null) return worker; worker = new Worker(); worker.start(); return worker; } private long timeout; private Hashtable data = new Hashtable(); /** * Erzeugt eine Session mit dem Default-Timeout von 30 Minuten. */ public Session() { this(1000l * 60 * 30); } /** * ct. * @param timeout Anzahl der Millisekunden, nach deren Ablauf ein Element wieder entfernt werden soll. */ public Session(long timeout) { Logger.debug("creating new session. default timeout: " + timeout + " millis"); this.timeout = timeout; getWorker().register(this); } /** * Liefert eine Liste aller in der Session vorhandenen Schluessel. * @return Liste der Schluessel. */ public Enumeration keys() { return data.keys(); } /** * Speichert einen Wert unter dem angegebenen Schluessel in der Session mit dem Default-Timeout. * Das Objekt wird nur dann nach Ablauf des Timeouts entfernt, wenn es innerhalb dieses * Zeitraumes nicht benutzt wurde. * @param key Name des Schluessels. * @param value Wert des Schluessels. */ public void put(Object key, Object value) { put(key,value,this.timeout); } /** * Speichert einen Wert unter dem angegebenen Schluessel in der Session mit einem Timeoout. * Das Objekt wird nur dann nach Ablauf des Timeouts entfernt, wenn es innerhalb dieses * Zeitraumes nicht benutzt wurde. * @param key Name des Schluessels. * @param value Wert des Schluessels. * @param t Timeout in Millisekunden. */ public void put(Object key, Object value, long t) { data.put(key,new SessionObject(value,t,false)); } /** * Speichert einen Wert unter dem angegebenen Schluessel in der Session mit einem * konkreten Ziel-Datum fuer das Timeout. * Unabhaengig davon, ob das Objekt benutzt wird oder nicht, wird es zum angegebenen * Timeout entfernt. * @param key Name des Schluessels. * @param value Wert des Schluessels. * @param t Timeout als Datum. */ public void put(Object key, Object value, Date t) { data.put(key,new SessionObject(value, t.getTime(),true)); } /** * Liefert Wert aus der Session, der unter dem angegebenen Namen gespeichert ist. * @param key Name des Schluessels in der Session. * @return Wert des Schluessels. */ public Object get(Object key) { synchronized(data) { SessionObject o = (SessionObject) data.get(key); return o == null ? null : o.getValue(); } } /** * Liefert Wert aus der Session, der unter dem angegebenen Namen gespeichert ist * und entfernt den Wert gleichzeitig. * @param key Name des Schluessels in der Session. * @return Wert des Schluessels. */ public Object remove(Object key) { synchronized(data) { SessionObject o = (SessionObject) data.remove(key); return o == null ? null : o.value; } } /** * Leert die Session. */ public void clear() { synchronized (data) { data.clear(); } } /** * Liefert die Anzahl der Elemente in der Session. * @return Anzahl der Elemente. */ public int size() { synchronized(data) { return data.size(); } } /** * @see java.lang.Object#finalize() */ protected void finalize() throws Throwable { getWorker().unregister(this); super.finalize(); } private class SessionObject { private Object value; private long timestamp = System.currentTimeMillis(); private long myTimeout = timeout; private boolean hardTimeout = false; private SessionObject(Object value, long t, boolean hardTimeout) { this.value = value; this.hardTimeout = hardTimeout; if (this.hardTimeout) { Logger.trace("added object \"" + value + "\" to session. hard timeout: " + new Date(t).toString()); this.timestamp = t; this.myTimeout = 0; } else { this.myTimeout = t; Logger.trace("added object \"" + value + "\" to session. timeout: " + t + " millis"); } } /** * Liefert den Wert des Keys. * @return der Wert. */ private Object getValue() { if (!hardTimeout) this.timestamp = System.currentTimeMillis(); return this.value; } } /** * Der Worker-Thread. * @author willuhn */ private final static class Worker extends Thread { private ArrayList sessions = new ArrayList(); /** * ct. */ public Worker() { super("Session Worker Thread"); Logger.debug("Starting Session Worker Thread"); } /** * Registriert eine neue Session in dem Worker. * @param session */ private void register(Session session) { synchronized(this.sessions) { if (!this.sessions.contains(session)) this.sessions.add(session); } } /** * Entfernt eine Session aus dem Worker. * @param session die Session. */ private void unregister(Session session) { synchronized(this.sessions) { this.sessions.remove(session); if (this.sessions.size() == 0) { // wir haben keine Sessions mehr. Dann koennen wir uns beenden. try { Logger.debug("session worker thread no longer needed, shutting down"); interrupt(); } catch (Exception e) { Logger.error("unable to shut down worker thread",e); } finally { Session.worker = null; } } } } /** * @see java.lang.Runnable#run() */ public void run() { try { while (!this.isInterrupted()) { long current = System.currentTimeMillis(); synchronized(this.sessions) { for (int i=0;i (value.timestamp + value.myTimeout)) { Logger.trace("removing object " + key + " from session"); data.remove(key); s.setChanged(); s.notifyObservers(value.value); } } } } } sleep(1000l); } } catch (InterruptedException e) { Logger.debug("session worker thread interrupted"); } } } } /********************************************************************* * $Log: Session.java,v $ * Revision 1.13 2009/11/24 10:48:18 willuhn * @N Session#clear * * Revision 1.12 2007/11/26 15:11:36 willuhn * @B Objekte in Session liefen nicht ab * * Revision 1.11 2006/09/05 22:02:01 willuhn * @C Worker-Redesign in Settings und Session * * Revision 1.10 2006/09/05 20:40:11 willuhn * @N Worker-Thread Redesign * * Revision 1.9 2006/04/26 15:04:13 web0 * *** empty log message *** * * Revision 1.8 2006/04/05 09:00:41 web0 * *** empty log message *** * * Revision 1.7 2005/09/04 21:50:27 web0 * *** empty log message *** * * Revision 1.6 2005/07/25 22:12:45 web0 * *** empty log message *** * * Revision 1.5 2005/07/24 16:59:17 web0 * @B fix in settings watcher * * Revision 1.4 2005/07/08 16:42:31 web0 * *** empty log message *** * * Revision 1.3 2005/04/28 15:43:33 web0 * *** empty log message *** * * Revision 1.2 2005/04/04 17:51:09 web0 * @N new Session * **********************************************************************/util-V_2_8_BUILD_217/src/de/willuhn/util/Settings.java000077500000000000000000000422331327231031700225050ustar00rootroot00000000000000/********************************************************************** * * Copyright (c) by Olaf Willuhn * GPLv2 * **********************************************************************/ package de.willuhn.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Properties; import de.willuhn.io.IOUtil; import de.willuhn.logging.Logger; /** * Diese Klasse erweitert Java-Properties um Typsicherheit fuer primitive * Typen, Support zum Laden und Speichern von String-Arrays, automatisches * Abspeichern beim Aufruf einer Set-Methode und sogar Speichern schon * beim Lesen. Das ist nuetzlich, wenn man eine Software ohne properties-Dateien * ausliefern will aber dennoch nach dem ersten Start beim Benutzer die * Config-Dateien mit den Default-Werten angelegt werden damit dieser * nicht in der Dokumentation nach den Schluesselnamen suchen muss * sondern sie bereits mit Default-Werten in den Dateien vorfindet. * Wird die Properties-Datei von aussen (z.Bsp. mit einem Texteditor) * geaendert, wird das automatisch erkannt und die Datei intern neu geladen. * @author willuhn */ public class Settings { private File file = null; private double lastModified = 0; private Properties properties = null; // Bei Gelegenheit mal auf TypedProperties umstellen private boolean storeWhenRead = false; /** * Erzeugt eine neue Instanz der Settings, die exclusiv * nur fuer diese Klasse gelten. Existieren bereits Settings * fuer die Klasse, werden sie gleich geladen. * Hierbei wird eine Properties-Datei * [classname].properties im angegebenen Verzeichnis angelegt. * @param path Pfad zu den Einstellungen. * @param clazz Klasse, fuer die diese Settings gelten. */ public Settings(String path, Class clazz) { this(null,path,clazz); } /** * Erzeugt eine neue Instanz der Settings, die exclusiv * nur fuer diese Klasse gelten. Existieren bereits Settings * fuer die Klasse, werden sie gleich geladen. * Hierbei wird eine Properties-Datei * [classname].properties im angegebenen Verzeichnis angelegt. * @param systemPath Pfad zu ggf vorhandenen System-Presets. * @param userPath Pfad zu den User-Einstellungen. * @param clazz Klasse, fuer die diese Settings gelten. */ public Settings(String systemPath, String userPath, Class clazz) { this( (systemPath != null ? new File(systemPath + File.separator + clazz.getName() + ".properties") : null), new File(userPath + File.separator + clazz.getName() + ".properties") ); } /** * Erzeugt eine neue Instanz. * @param systemFile Properties-Datei mit den System-Vorgaben. * @param userFile Properties-Datei des Users, welche die System-Vorgaben ueberschreiben. */ public Settings(File systemFile, File userFile) { // Filenamen ermitteln this.file = userFile; this.properties = new Properties(); // Checken, ob System-Presets existieren if (systemFile != null) { if (systemFile.exists() && systemFile.canRead()) { InputStream is = null; try { // "this.properties" wird initial mit den System-Vorgaben befuellt. // Wenn der User eigene Werte definiert hat, ersetzen seine Werte anschliessend // in "reload()" die System-Vorgaben Logger.debug("loading system presets from " + systemFile.getAbsolutePath()); Properties presets = new Properties(); is = new BufferedInputStream(new FileInputStream(systemFile)); presets.load(is); this.properties.putAll(presets); } catch (Exception e1) { Logger.error("unable to load system presets from " + systemFile.getAbsolutePath(),e1); } finally { IOUtil.close(is); } } } // Parameter laden, wenn die Datei existiert if (this.file != null && this.file.exists()) reload(); } /** * Legt fest, ob die Einstellungen schon beim Lesen gespeichert werden sollen. * Hintergrund: Jede Get-Funktion (getString(), getBoolean(),..) besitzt einen * Parameter mit dem Default-Wert falls der Parameter noch nicht existiert. * Ist dies der Fall und die zugehoerige Set-Methode wird nie aufgerufen, * dann erscheint der Parameter nie physisch in der properties-Datei. * Diese muesste dann manuell mit den Parametern befuellt werden, um * sie aendern zu koennen. Da die Parameter-Namen aber nur in der * Java-Klasse bekannt sind, wird es einem Fremden schwer fallen, die * Namen der Parameter zu ermitteln. Fuer genau diesen Fall kann der * Parameter auf true gesetzt werden. Alle abgefragten Parameter, werden * dann nach der Abfrage mit dem aktuellen Wert (ggf. dem Default-Wert) * sofort gespeichert. * Der Default-Wert ist "false". Per Default wird beim Lesen also nicht geschrieben. * @param b true, wenn sofort geschrieben werden soll. */ public void setStoreWhenRead(boolean b) { this.storeWhenRead = b; } /** * Liefert eine Liste aller Attribut-Namen, die in dieser Settings-Instanz gespeichert wurden. * @return Liste der Attribut-Namen. */ public String[] getAttributes() { reload(); synchronized (properties) { Iterator it = properties.keySet().iterator(); String[] attributes = new String[properties.size()]; int i = 0; while (it.hasNext()) { attributes[i++] = (String) it.next(); } return attributes; } } /** * Liefert den Wert des genannten Attributs als Boolean. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return true oder false. */ public boolean getBoolean(String name, boolean defaultValue) { reload(); String def = Boolean.toString(defaultValue); String s = this.properties.getProperty(name, def); if (s != null) s = s.trim(); // BUGZILLA 477 boolean b = "true".equalsIgnoreCase(s); storeConditional(name,Boolean.toString(b)); return b; } /** * Liefert den Wert des genannten Attributs als int. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Hinweis: Die Funktion wirft keine NumberFormat-Exception, wenn der * Wert nicht in eine Zahl gewandelt werden kann. Stattdessen wird der * Default-Wert zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public int getInt(String name, int defaultValue) { reload(); String def = Integer.toString(defaultValue); String s = this.properties.getProperty(name,def); if (s != null) s = s.trim(); // BUGZILLA 477 int i = defaultValue; try { i = Integer.parseInt(s); } catch (NumberFormatException e) { Logger.error("unable to parse value of param \"" + name + "\", value: " + s,e); } storeConditional(name,Integer.toString(i)); return i; } /** * Liefert den Wert des genannten Attributs als long. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Hinweis: Die Funktion wirft keine NumberFormat-Exception, wenn der * Wert nicht in eine Zahl gewandelt werden kann. Stattdessen wird der * Default-Wert zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public long getLong(String name, long defaultValue) { reload(); String def = Long.toString(defaultValue); String s = this.properties.getProperty(name,def); if (s != null) s = s.trim(); // BUGZILLA 477 long l = defaultValue; try { l = Long.parseLong(s); } catch (NumberFormatException e) { Logger.error("unable to parse value of param \"" + name + "\", value: " + s,e); } storeConditional(name,Long.toString(l)); return l; } /** * Liefert den Wert des genannten Attributs als double. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Hinweis: Die Funktion wirft keine NumberFormat-Exception, wenn der * Wert nicht in eine Zahl gewandelt werden kann. Stattdessen wird der * Default-Wert zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public double getDouble(String name, double defaultValue) { reload(); String def = "" + defaultValue; String s = this.properties.getProperty(name,def); if (s != null) s = s.trim(); // BUGZILLA 477 double d = defaultValue; try { d = Double.parseDouble(s); } catch (NumberFormatException e) { Logger.error("unable to parse value of param \"" + name + "\", value: " + s,e); } storeConditional(name,"" + d); return d; } /** * Liefert den Wert des Attribute. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public String getString(String name, String defaultValue) { reload(); String s = this.properties.getProperty(name,defaultValue); storeConditional(name,s); return s; } /** * Liefert ein Array von Werten. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Es koennen maximal 256 Werte gelesen oder gespeichert werden. * @param name Name des Attributs. * @param defaultValues DefaultWert, wenn das Attribut nicht existiert. * @return Werte des Attributs in Form eines String-Arrays. */ public String[] getList(String name, String[] defaultValues) { reload(); String[] result = this.getList(name); if (result.length == 0) { storeConditional(name,defaultValues); return defaultValues; } storeConditional(name,result); return result; } /** * Liefert das Array mit den Werten. * @param name Name des Attributs. * @return Werte des Attributs. */ private String[] getList(String name) { List l = new ArrayList(); String s = null; for (int i=0;i<255;++i) { s = this.properties.getProperty(name + "." + i,null); if (s == null) continue; l.add(s); } return l.toArray(new String[l.size()]); } /** * Speichert einen boolschen Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setAttribute(String name, boolean value) { setAttribute(name, Boolean.toString(value)); } /** * Speichert einen Integer-Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setAttribute(String name, int value) { setAttribute(name,Integer.toString(value)); } /** * Speichert einen Double-Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setAttribute(String name, double value) { setAttribute(name,""+value); } /** * Speichert einen Long-Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setAttribute(String name, long value) { setAttribute(name,Long.toString(value)); } /** * Speichert das Attribut mit dem zugehoerigen Wert . * Wenn ein gleichnamiges Attribut bereits existiert, wird es ueberschrieben. * Ist der Wert des Attributes null, wird es entfernt. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setAttribute(String name, String value) { // Wir speichern nur, wenn etwas geaendert wurde if (value == null) { String prev = (String) properties.remove(name); // Wir haben wirklich was geloescht if (prev != null) store(); } else { String prev = (String) properties.setProperty(name,value); // vorher existierte der Parameter nicht, oder er war anders if (prev == null || !value.equals(prev)) store(); } } /** * Speichert das Attribut mit der zugehoerigen Liste von Werten . * Wenn ein gleichnamiges Attribut bereits existiert, werden dessen Werte ueberschrieben. * Ist der Wert des Attributes null, wird es entfernt. * Von dem Array werden die ersten maximal 256 Elemente gespeichert. * Alle darueber hinausgehenden Werte, werden ignoriert. * @param name Name des Attributs. * @param values Werte des Attributs. */ public void setAttribute(String name, String[] values) { // Wir entfernen immer erst alle Werte. Denn wenn vorher // ein laengeres Array drin steht, als wir jetzt reinschreiben, // wuerden die alten Werte am Ende des grossen Arrays nicht mehr // entfernt. for (int i=0;i<255;++i) { this.properties.remove(name + "." + i); } if (values == null || values.length == 0) { store(); return; } for (int i=0;i= 255) break; // Schluss jetzt. Das waren genug Werte ;) if (values[i] == null) continue; // NULL-Werte ueberspringen properties.setProperty(name + "." + i,values[i]); } store(); } /** * Speichert die Datei mit dem geaenderten Parameter nur dann, * wenn sich zum aktuellen Inhalt tatsaechlich etwas geaendert hat. * @param name der Name des Parameters. * @param value der aktuelle Wert. */ private void storeConditional(String name, String value) { // koennen wir uns komplett schenken if (!this.storeWhenRead) return; // Wir muessen nur speichern, wenn sie aktueller und hinterlegter Wert unterscheiden String old = this.properties.getProperty(name); // Es hat sich nichts geaendert if (value == null ? old == null : value.equals(old)) return; // Aenderung speichern this.setAttribute(name,value); } /** * Speichert die Datei mit dem geaenderten Parameter nur dann, * wenn sich zum aktuellen Inhalt tatsaechlich etwas geaendert hat. * @param name der Name des Parameters. * @param value der aktuelle Wert. */ private void storeConditional(String name, String[] values) { // koennen wir uns komplett schenken if (!this.storeWhenRead) return; // Wir muessen nur speichern, wenn sie aktueller und hinterlegter Wert unterscheiden String[] old = this.getList(name); // Diese Funktion macht den kompletten Vergleich selbst // Vor dem Vergleich der Elemente prueft sie auch, ob eines // von beiden NULL ist und ob beide die gleiche Groesse haben // Der Inhaltsvergleich findet da drin nur statt, wenn beide // nicht NULL sind und die gleiche Groesse haben. if (Arrays.equals(values,old)) return; // Aenderung speichern this.setAttribute(name,values); } /** * Schreibt die Properties in die Datei. * Hinweis: Die Funktion wirft keine IOException, wenn die Datei nicht * gespeichert werden kann. Stattdessen wird der Fehler lediglich geloggt. */ private synchronized void store() { // Die Datei existiert noch nicht und wir haben noch keine Werte. // Dann muessen wir die Datei auch nicht sinnlos anlegen if (this.file == null || !this.file.exists() && this.properties.size() == 0) return; OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(this.file)); Logger.debug("saving " + this.file.getAbsolutePath()); this.properties.store(os,null); } catch (Exception e1) { Logger.error("unable to store settings. Do you have write permissions in " + this.file.getAbsolutePath() + " ?",e1); } finally { this.lastModified = this.file.lastModified(); if (os != null) { try { os.close(); } catch (Exception e) { Logger.error("unable to close settings file: " + this.file.getAbsolutePath(),e); } } } } /** * Laedt die Datei neu. */ private synchronized void reload() { if (this.file == null) return; long modified = this.file.lastModified(); if (this.lastModified == modified) return; // Kein Reload noetig InputStream is = null; try { if (this.lastModified > 0) // wenn lastModified 0 ist, wurde die Datei noch gar nicht geladen Logger.debug(this.file.getAbsolutePath() + " has changed, reloading"); is = new BufferedInputStream(new FileInputStream(this.file)); this.properties.load(is); } catch (FileNotFoundException nfe) { Logger.warn("file " + this.file.getAbsolutePath() + " has been deleted"); this.properties.clear(); } catch (Exception e1) { Logger.error("unable to (re)load settings. Do you have read permissions in " + this.file.getAbsolutePath() + " ?",e1); } finally { this.lastModified = modified; IOUtil.close(is); } } } util-V_2_8_BUILD_217/src/de/willuhn/util/TypedProperties.java000066400000000000000000000172121327231031700240430ustar00rootroot00000000000000/********************************************************************** * $Source: /cvsroot/jameica/util/src/de/willuhn/util/TypedProperties.java,v $ * $Revision: 1.1 $ * $Date: 2011/08/10 09:43:40 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn.webdesign * All rights reserved * **********************************************************************/ package de.willuhn.util; import java.util.ArrayList; import java.util.List; import java.util.Properties; import de.willuhn.logging.Logger; /** * Diese Klasse erweitert Java-Properties um Typsicherheit fuer primitive Typen. */ public class TypedProperties extends Properties { /** * Liefert den Wert des genannten Attributs als Boolean. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return true oder false. */ public boolean getBoolean(String name, boolean defaultValue) { String s = this.getInternal(name,defaultValue ? "true" : "false"); return "true".equalsIgnoreCase(s); } /** * Liefert den Wert des genannten Attributs als int. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Hinweis: Die Funktion wirft keine NumberFormat-Exception, wenn der * Wert nicht in eine Zahl gewandelt werden kann. Stattdessen wird der * Default-Wert zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public int getInt(String name, int defaultValue) { String s = this.getInternal(name,Integer.toString(defaultValue)); try { return Integer.parseInt(s); } catch (NumberFormatException e) { Logger.error("unable to parse " + name + "=" + s + " as integer",e); } return defaultValue; } /** * Liefert den Wert des genannten Attributs als long. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Hinweis: Die Funktion wirft keine NumberFormat-Exception, wenn der * Wert nicht in eine Zahl gewandelt werden kann. Stattdessen wird der * Default-Wert zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public long getLong(String name, long defaultValue) { String s = this.getInternal(name,Long.toString(defaultValue)); try { return Long.parseLong(s); } catch (NumberFormatException e) { Logger.error("unable to parse " + name + "=" + s + " as long",e); } return defaultValue; } /** * Liefert den Wert des genannten Attributs als double. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Hinweis: Die Funktion wirft keine NumberFormat-Exception, wenn der * Wert nicht in eine Zahl gewandelt werden kann. Stattdessen wird der * Default-Wert zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public double getDouble(String name, double defaultValue) { String s = this.getInternal(name,Double.toString(defaultValue)); try { return Double.parseDouble(s); } catch (NumberFormatException e) { Logger.error("unable to parse " + name + "=" + s + " as double",e); } return defaultValue; } /** * Liefert den Wert des Attribute. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * @param name Name des Attributs. * @param defaultValue DefaultWert, wenn das Attribut nicht existiert. * @return der Wert des Attributs. */ public String getString(String name, String defaultValue) { return this.getInternal(name,defaultValue); } /** * Liefert ein Array von Werten. * Wird das Attribut nicht gefunden oder hat keinen Wert, wird defaultValue zurueckgegeben. * Es koennen maximal 256 Werte gelesen oder gespeichert werden. * @param name Name des Attributs. * @param defaultValues DefaultWert, wenn das Attribut nicht existiert. * @return Werte des Attributs in Form eines String-Arrays. */ public String[] getList(String name, String[] defaultValues) { List l = new ArrayList(); String s = null; for (int i=0;i<255;++i) { s = this.getInternal(name + "." + i,null); if (s == null) continue; l.add(s); } return l.size() > 0 ? l.toArray(new String[l.size()]) : defaultValues; } /** * Speichert einen boolschen Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setBoolean(String name, boolean value) { this.setInternal(name, value ? "true" : "false"); } /** * Speichert einen Integer-Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setInt(String name, int value) { this.setInternal(name,Integer.toString(value)); } /** * Speichert einen Double-Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setDouble(String name, double value) { this.setInternal(name,Double.toString(value)); } /** * Speichert einen Long-Wert. * @param name Name des Attributs. * @param value Wert des Attributs. */ public void setLong(String name, long value) { this.setInternal(name,Long.toString(value)); } /** * Speichert das Attribut mit der zugehoerigen Liste von Werten. * Wenn ein gleichnamiges Attribut bereits existiert, werden dessen Werte ueberschrieben. * Ist der Wert des Attributes null, wird es entfernt. * Von dem Array werden die ersten maximal 256 Elemente gespeichert. * Alle darueber hinausgehenden Werte, werden ignoriert. * @param name Name des Attributs. * @param values Werte des Attributs. */ public void setList(String name, String[] values) { // Wir entfernen immer erst alle Werte. Denn wenn vorher // ein laengeres Array drin steht, als wir jetzt reinschreiben, // wuerden die alten Werte am Ende des grossen Arrays nicht mehr // entfernt. for (int i=0;i<255;++i) { super.remove(name + "." + i); } // Keine neuen zu speichern if (values == null || values.length == 0) return; for (int i=0;i= 255) break; // Schluss jetzt. Das waren genug Werte ;) if (values[i] == null) continue; // NULL-Werte ueberspringen super.setProperty(name + "." + i,values[i]); } } /** * Liefert den Wert des Attributes. * @param name * @param defaultValue * @return der Wert des Attributes. */ private String getInternal(String name, String defaultValue) { String s = super.getProperty(name, defaultValue); if (s != null) s = s.trim(); return s; } /** * Speichert das Attribut "name" mit dem zugehoerigen Wert "value". * Wenn ein gleichnamiges Attribut bereits existiert, wird es ueberschrieben. * Ist der Wert des Attributes null, wird es entfernt. * @param name Name des Attributs. * @param value Wert des Attributs. */ private void setInternal(String name, String value) { // Wir speichern nur, wenn etwas geaendert wurde if (value == null) super.remove(name); else super.setProperty(name,value); } } /********************************************************************* * $Log: TypedProperties.java,v $ * Revision 1.1 2011/08/10 09:43:40 willuhn * @N TypedProperties * **********************************************************************/