This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.catalina.tribes.ChannelMessage;
import org.apache.catalina.tribes.Member;
import org.apache.catalina.tribes.UniqueId;
import org.apache.catalina.tribes.group.AbsoluteOrder;
import org.apache.catalina.tribes.membership.Membership;
/**
* @version 1.0
*/
public class Arrays {
protected static final StringManager sm = StringManager.getManager(Arrays.class);
public static boolean contains(byte[] source, int srcoffset, byte[] key, int keyoffset, int length) {
if ( srcoffset < 0 || srcoffset >= source.length) throw new ArrayIndexOutOfBoundsException(sm.getString("arrays.srcoffset.outOfBounds"));
if ( keyoffset < 0 || keyoffset >= key.length) throw new ArrayIndexOutOfBoundsException(sm.getString("arrays.keyoffset.outOfBounds"));
if ( length > (key.length-keyoffset) ) throw new ArrayIndexOutOfBoundsException(sm.getString("arrays.length.outOfBounds"));
//we don't have enough data to validate it
if ( length > (source.length-srcoffset) ) return false;
boolean match = true;
int pos = keyoffset;
for ( int i=srcoffset; match && i<length; i++ ) {
match = (source[i] == key[pos++]);
}
return match;
}
public static String toString(byte[] data) {
return toString(data,0,data!=null?data.length:0);
}
public static String toString(byte[] data, int offset, int length) {
return toString(data,offset,length,false);
}
public static String toString(byte[] data, int offset, int length, boolean unsigned) {
StringBuilder buf = new StringBuilder("{");
if ( data != null && length > 0 ) {
int i = offset;
if (unsigned) {
buf.append(data[i++] & 0xff);
for (; i < length; i++) {
buf.append(", ").append(data[i] & 0xff);
}
} else {
buf.append(data[i++]);
for (; i < length; i++) {
buf.append(", ").append(data[i]);
}
}
}
buf.append("}");
return buf.toString();
}
public static String toString(Object[] data) {
return toString(data,0,data!=null?data.length:0);
}
public static String toString(Object[] data, int offset, int length) {
StringBuilder buf = new StringBuilder("{");
if ( data != null && length > 0 ) {
buf.append(data[offset++]);
for (int i = offset; i < length; i++) {
buf.append(", ").append(data[i]);
}
}
buf.append("}");
return buf.toString();
}
public static String toNameString(Member[] data) {
return toNameString(data,0,data!=null?data.length:0);
}
public static String toNameString(Member[] data, int offset, int length) {
StringBuilder buf = new StringBuilder("{");
if ( data != null && length > 0 ) {
buf.append(data[offset++].getName());
for (int i = offset; i < length; i++) {
buf.append(", ").append(data[i].getName());
}
}
buf.append("}");
return buf.toString();
}
public static int add(int[] data) {
int result = 0;
for (int i=0;i<data.length; i++ ) result += data[i];
return result;
}
public static UniqueId getUniqudId(ChannelMessage msg) {
return new UniqueId(msg.getUniqueId());
}
public static UniqueId getUniqudId(byte[] data) {
return new UniqueId(data);
}
public static boolean equals(byte[] o1, byte[] o2) {
return java.util.Arrays.equals(o1,o2);
}
public static boolean equals(Object[] o1, Object[] o2) {
boolean result = o1.length == o2.length;
if ( result ) for (int i=0; i<o1.length && result; i++ ) result = o1[i].equals(o2[i]);
return result;
}
public static boolean sameMembers(Member[] m1, Member[] m2) {
AbsoluteOrder.absoluteOrder(m1);
AbsoluteOrder.absoluteOrder(m2);
return equals(m1,m2);
}
public static Member[] merge(Member[] m1, Member[] m2) {
AbsoluteOrder.absoluteOrder(m1);
AbsoluteOrder.absoluteOrder(m2);
ArrayList<Member> list = new ArrayList<>(java.util.Arrays.asList(m1));
for (int i=0; i<m2.length; i++) if ( !list.contains(m2[i]) ) list.add(m2[i]);
Member[] result = new Member[list.size()];
list.toArray(result);
AbsoluteOrder.absoluteOrder(result);
return result;
}
public static void fill(Membership mbrship, Member[] m) {
for (int i=0; i<m.length; i++ ) mbrship.addMember(m[i]);
}
public static Member[] diff(Membership complete, Membership local, Member ignore) {
ArrayList<Member> result = new ArrayList<>();
Member[] comp = complete.getMembers();
for ( int i=0; i<comp.length; i++ ) {
if ( ignore!=null && ignore.equals(comp[i]) ) continue;
if ( local.getMember(comp[i]) == null ) result.add(comp[i]);
}
return result.toArray(new Member[result.size()]);
}
public static Member[] remove(Member[] all, Member remove) {
return extract(all,new Member[] {remove});
}
public static Member[] extract(Member[] all, Member[] remove) {
List<Member> alist = java.util.Arrays.asList(all);
ArrayList<Member> list = new ArrayList<>(alist);
for (int i=0; i<remove.length; i++ ) list.remove(remove[i]);
return list.toArray(new Member[list.size()]);
}
public static int indexOf(Member member, Member[] members) {
int result = -1;
for (int i=0; (result==-1) && (i<members.length); i++ )
if ( member.equals(members[i]) ) result = i;
return result;
}
public static int nextIndex(Member member, Member[] members) {
int idx = indexOf(member,members)+1;
if (idx >= members.length ) idx = ((members.length>0)?0:-1);
return idx;
}
public static int hashCode(byte a[]) {
if (a == null)
return 0;
int result = 1;
for (int i=0; i<a.length; i++) {
byte element = a[i];
result = 31 * result + element;
}
return result;
}
public static byte[] fromString(String value) {
if ( value == null ) return null;
if ( !value.startsWith("{") ) throw new RuntimeException(sm.getString("arrays.malformed.arrays"));
StringTokenizer t = new StringTokenizer(value,"{,}",false);
byte[] result = new byte[t.countTokens()];
for (int i=0; i<result.length; i++ ) result[i] = Byte.parseByte(t.nextToken());
return result;
}
public static byte[] convert(String s) {
return s.getBytes(StandardCharsets.ISO_8859_1);
}
}

View File

@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
/**
* Utilities for handling Throwables and Exceptions.
*/
public class ExceptionUtils {
/**
* Checks whether the supplied Throwable is one that needs to be
* rethrown and swallows all others.
* @param t the Throwable to check
*/
public static void handleThrowable(Throwable t) {
if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
}
if (t instanceof StackOverflowError) {
// Swallow silently - it should be recoverable
return;
}
if (t instanceof VirtualMachineError) {
throw (VirtualMachineError) t;
}
// All other instances of Throwable will be silently swallowed
}
}

View File

@@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ExecutorFactory {
protected static final StringManager sm = StringManager.getManager(ExecutorFactory.class);
public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit) {
TaskQueue taskqueue = new TaskQueue();
ThreadPoolExecutor service = new TribesThreadPoolExecutor(minThreads, maxThreads, maxIdleTime, unit,taskqueue);
taskqueue.setParent(service);
return service;
}
public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit, ThreadFactory threadFactory) {
TaskQueue taskqueue = new TaskQueue();
ThreadPoolExecutor service = new TribesThreadPoolExecutor(minThreads, maxThreads, maxIdleTime, unit,taskqueue, threadFactory);
taskqueue.setParent(service);
return service;
}
// ---------------------------------------------- TribesThreadPoolExecutor Inner Class
private static class TribesThreadPoolExecutor extends ThreadPoolExecutor {
public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
public void execute(Runnable command) {
try {
super.execute(command);
} catch (RejectedExecutionException rx) {
if (super.getQueue() instanceof TaskQueue) {
TaskQueue queue = (TaskQueue)super.getQueue();
if (!queue.force(command)) {
throw new RejectedExecutionException(sm.getString("executorFactory.queue.full"));
}
}
}
}
}
// ---------------------------------------------- TaskQueue Inner Class
private static class TaskQueue extends LinkedBlockingQueue<Runnable> {
private static final long serialVersionUID = 1L;
transient ThreadPoolExecutor parent = null;
public TaskQueue() {
super();
}
public void setParent(ThreadPoolExecutor tp) {
parent = tp;
}
public boolean force(Runnable o) {
if ( parent.isShutdown() ) throw new RejectedExecutionException(sm.getString("executorFactory.not.running"));
return super.offer(o); //forces the item onto the queue, to be used if the task is rejected
}
@Override
public boolean offer(Runnable o) {
//we can't do any checks
if (parent==null) return super.offer(o);
//we are maxed out on threads, simply queue the object
if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
//we have idle threads, just add it to the queue
//this is an approximation, so it could use some tuning
if (parent.getActiveCount()<(parent.getPoolSize())) return super.offer(o);
//if we have less threads than maximum force creation of a new thread
if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
//if we reached here, we need to add it to the queue
return super.offer(o);
}
}
}

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=keyoffset is out of bounds.
arrays.length.outOfBounds=not enough data elements in the key, length is out of bounds.
arrays.malformed.arrays=byte arrays must be represented as {1,3,4,5,6}
arrays.srcoffset.outOfBounds=srcoffset is out of bounds.
executorFactory.not.running=Executor not running, can't force a command into the queues
executorFactory.queue.full=Queue capacity is full.
uuidGenerator.createRandom=Creation of SecureRandom instance for UUID generation using [{0}] took [{1}] milliseconds.
uuidGenerator.unable.fit=Unable to fit [{0}] bytes into the array. length:[{1}] required length:[{2}]

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=keyoffset ist Außerhalb der gültigen Grenzen

View File

@@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=keyoffset esta fura de los límites.\n
arrays.length.outOfBounds=no hay suficientes elementos de datos en la llave, la longitud es fuera de los límites
executorFactory.not.running=Ejecutor no esta corriendo, no se puede forzar un comando dentro le as colas

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=Le décalage (offset) de la clé est en-dehors des limites.
arrays.length.outOfBounds=Pas assez de données dans la clé, la longueur dépasse les limites
arrays.malformed.arrays=les tableaux d'octets doivent être représentés tels que {1,3,4,5,6}
arrays.srcoffset.outOfBounds=srcoffset est hors limites
executorFactory.not.running=L'Executor ne tourne pas, impossible de forcer une commande dans les files d'attente
executorFactory.queue.full=La file d'attente est complète
uuidGenerator.createRandom=La création d''une instance de SecureRandom pour le génération des UUID en utilisant [{0}] a pris [{1}] millisecondes
uuidGenerator.unable.fit=Impossible de faire rentrer [{0}] octets dans le tableau, longueur: [{1}] longueur requise: [{2}]

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=keyoffset が領域外を指しています。
arrays.length.outOfBounds=キー配列のデータ要素が不足しています。length が境界を超えました。
arrays.malformed.arrays=バイト配列は{1,3,4,5,6}のような表現でなければなりません。
arrays.srcoffset.outOfBounds=srcoffsetが範囲外です。
executorFactory.not.running=エグゼキュータが実行されていないので、キューにコマンドを強制することはできません
executorFactory.queue.full=キューの容量がいっぱいです。
uuidGenerator.createRandom=[{0}]を使用してUUID生成用のSecureRandomインスタンスを作成すると、[{1}]ミリ秒かかりました。
uuidGenerator.unable.fit=[{0}] バイトを配列に合わせることができません。現在のサイズは [{1}] で必要なサイズは [{2}] です。

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=keyoffset이 범위를 초과합니다.
arrays.length.outOfBounds=키 내에 충분한 데이터 엘리먼트들이 존재하지 않습니다. 길이가 범위 밖에 있습니다.
arrays.malformed.arrays=바이트 배열은 반드시 ''{1,3,4,5,6}''과 같이 표현되어야 합니다.
arrays.srcoffset.outOfBounds=srcoffset이 범위 밖입니다.
executorFactory.not.running=Executor가 실행 중이 아닙니다. 명령을 강제로 큐에 넣을 수 없습니다.
executorFactory.queue.full=큐의 용량이 꽉 찼습니다.
uuidGenerator.createRandom=[{0}]을(를) 사용하여, UUID 생성을 위한 SecureRandom 인스턴스를 생성하는 데에, [{1}] 밀리초가 소요됐습니다.
uuidGenerator.unable.fit=[{0}] 바이트를 해당 배열에 맞출 수 없습니다. 길이:[{1}], 요구되는 길이:[{2}]

View File

@@ -0,0 +1,20 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
arrays.keyoffset.outOfBounds=key的偏移.超出了界限。
arrays.length.outOfBounds=当前key下没有足够的元素长度越界
executorFactory.not.running=执行器没有运行,无法强制把命令送入队列
executorFactory.queue.full=队列已满

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
*
* Simple class that holds references to global loggers
* @version 1.0
*/
public class Logs {
public static final Log MESSAGES = LogFactory.getLog("org.apache.catalina.tribes.MESSAGES");
}

View File

@@ -0,0 +1,281 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* An internationalization / localization helper class which reduces
* the bother of handling ResourceBundles and takes care of the
* common cases of message formating which otherwise require the
* creation of Object arrays and such.
*
* <p>The StringManager operates on a package basis. One StringManager
* per package can be created and accessed via the getManager method
* call.
*
* <p>The StringManager will look for a ResourceBundle named by
* the package name given plus the suffix of "LocalStrings". In
* practice, this means that the localized information will be contained
* in a LocalStrings.properties file located in the package
* directory of the classpath.
*
* <p>Please see the documentation for java.util.ResourceBundle for
* more information.
*
* @author James Duncan Davidson [duncan@eng.sun.com]
* @author James Todd [gonzo@eng.sun.com]
* @author Mel Martinez [mmartinez@g1440.com]
* @see java.util.ResourceBundle
*/
public class StringManager {
private static int LOCALE_CACHE_SIZE = 10;
/**
* The ResourceBundle for this StringManager.
*/
private final ResourceBundle bundle;
private final Locale locale;
/**
* Creates a new StringManager for a given package. This is a
* private method and all access to it is arbitrated by the
* static getManager method call so that only one StringManager
* per package will be created.
*
* @param packageName Name of package to create StringManager for.
*/
private StringManager(String packageName, Locale locale) {
String bundleName = packageName + ".LocalStrings";
ResourceBundle bnd = null;
try {
bnd = ResourceBundle.getBundle(bundleName, locale);
} catch (MissingResourceException ex) {
// Try from the current loader (that's the case for trusted apps)
// Should only be required if using a TC5 style classloader structure
// where common != shared != server
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null) {
try {
bnd = ResourceBundle.getBundle(bundleName, locale, cl);
} catch (MissingResourceException ex2) {
// Ignore
}
}
}
bundle = bnd;
// Get the actual locale, which may be different from the requested one
if (bundle != null) {
Locale bundleLocale = bundle.getLocale();
if (bundleLocale.equals(Locale.ROOT)) {
this.locale = Locale.ENGLISH;
} else {
this.locale = bundleLocale;
}
} else {
this.locale = null;
}
}
/**
* Get a string from the underlying resource bundle or return null if the
* String is not found.
*
* @param key to desired resource String
*
* @return resource String matching <i>key</i> from underlying bundle or
* null if not found.
*
* @throws IllegalArgumentException if <i>key</i> is null
*/
public String getString(String key) {
if (key == null){
String msg = "key may not have a null value";
throw new IllegalArgumentException(msg);
}
String str = null;
try {
// Avoid NPE if bundle is null and treat it like an MRE
if (bundle != null) {
str = bundle.getString(key);
}
} catch (MissingResourceException mre) {
//bad: shouldn't mask an exception the following way:
// str = "[cannot find message associated with key '" + key +
// "' due to " + mre + "]";
// because it hides the fact that the String was missing
// from the calling code.
//good: could just throw the exception (or wrap it in another)
// but that would probably cause much havoc on existing
// code.
//better: consistent with container pattern to
// simply return null. Calling code can then do
// a null check.
str = null;
}
return str;
}
/**
* Get a string from the underlying resource bundle and format
* it with the given set of arguments.
*
* @param key The key for the required message
* @param args The values to insert into the message
*
* @return The requested string formatted with the provided arguments
*/
public String getString(final String key, final Object... args) {
String value = getString(key);
if (value == null) {
value = key;
}
MessageFormat mf = new MessageFormat(value);
mf.setLocale(locale);
return mf.format(args, new StringBuffer(), null).toString();
}
/**
* Identify the Locale this StringManager is associated with
*
* @return The Locale associated with this instance
*/
public Locale getLocale() {
return locale;
}
// --------------------------------------------------------------
// STATIC SUPPORT METHODS
// --------------------------------------------------------------
private static final Map<String, Map<Locale,StringManager>> managers =
new Hashtable<>();
/**
* The StringManager will be returned for the package in which the class is
* located. If a manager for that package already exists, it will be reused,
* else a new StringManager will be created and returned.
*
* @param clazz The class for which to retrieve the StringManager
*
* @return The StringManager for the given class.
*/
public static final StringManager getManager(Class<?> clazz) {
return getManager(clazz.getPackage().getName());
}
/**
* If a manager for a package already exists, it will be reused, else a new
* StringManager will be created and returned.
*
* @param packageName The package name
*
* @return The StringManager for the given package.
*/
public static final StringManager getManager(String packageName) {
return getManager(packageName, Locale.getDefault());
}
/**
* If a manager for a package/Locale combination already exists, it will be
* reused, else a new StringManager will be created and returned.
*
* @param packageName The package name
* @param locale The Locale
*
* @return The StringManager for a particular package and Locale
*/
public static final synchronized StringManager getManager(
String packageName, Locale locale) {
Map<Locale,StringManager> map = managers.get(packageName);
if (map == null) {
/*
* Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE.
* Expansion occurs when size() exceeds capacity. Therefore keep
* size at or below capacity.
* removeEldestEntry() executes after insertion therefore the test
* for removal needs to use one less than the maximum desired size
*
*/
map = new LinkedHashMap<Locale,StringManager>(LOCALE_CACHE_SIZE, 1, true) {
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(
Map.Entry<Locale,StringManager> eldest) {
if (size() > (LOCALE_CACHE_SIZE - 1)) {
return true;
}
return false;
}
};
managers.put(packageName, map);
}
StringManager mgr = map.get(locale);
if (mgr == null) {
mgr = new StringManager(packageName, locale);
map.put(locale, mgr);
}
return mgr;
}
/**
* Retrieve the StringManager for a list of Locales. The first StringManager
* found will be returned.
*
* @param packageName The package for which the StringManager is required
* @param requestedLocales the list of Locales
*
* @return the found StringManager or the default StringManager
*/
public static StringManager getManager(String packageName,
Enumeration<Locale> requestedLocales) {
while (requestedLocales.hasMoreElements()) {
Locale locale = requestedLocales.nextElement();
StringManager result = getManager(packageName, locale);
if (result.getLocale().equals(locale)) {
return result;
}
}
// Return the default
return getManager(packageName);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* ThreadFactory implementation that creates threads with the thread context
* class loader set to the class loader that loaded this factory. It is intended
* to be used when tasks may be passed to executors when the web application
* class loader is set as the thread context class loader, such as in async
* session replication.
*/
public class TcclThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private static final boolean IS_SECURITY_ENABLED =
(System.getSecurityManager() != null);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TcclThreadFactory() {
this("pool-" + poolNumber.getAndIncrement() + "-thread-");
}
public TcclThreadFactory(String namePrefix) {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
this.namePrefix = namePrefix;
}
@Override
public Thread newThread(Runnable r) {
final Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
if (IS_SECURITY_ENABLED) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
t.setContextClassLoader(this.getClass().getClassLoader());
return null;
}
});
} else {
t.setContextClassLoader(this.getClass().getClassLoader());
}
t.setDaemon(true);
return t;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.tribes.util;
import java.security.SecureRandom;
import java.util.Random;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
* simple generation of a UUID
* @version 1.0
*/
public class UUIDGenerator {
private static final Log log = LogFactory.getLog(UUIDGenerator.class);
protected static final StringManager sm =
StringManager.getManager("org.apache.catalina.tribes.util");
public static final int UUID_LENGTH = 16;
public static final int UUID_VERSION = 4;
public static final int BYTES_PER_INT = 4;
public static final int BITS_PER_BYTE = 8;
protected static final SecureRandom secrand;
protected static final Random rand = new Random();
static {
long start = System.currentTimeMillis();
secrand = new SecureRandom();
// seed the generator
secrand.nextInt();
long time = System.currentTimeMillis() - start;
if (time > 100) {
log.info(sm.getString("uuidGenerator.createRandom",
secrand.getAlgorithm(), Long.valueOf(time)));
}
}
public static byte[] randomUUID(boolean secure) {
byte[] result = new byte[UUID_LENGTH];
return randomUUID(secure,result,0);
}
public static byte[] randomUUID(boolean secure, byte[] into, int offset) {
if ( (offset+UUID_LENGTH)>into.length )
throw new ArrayIndexOutOfBoundsException(sm.getString("uuidGenerator.unable.fit",
Integer.toString(UUID_LENGTH), Integer.toString(into.length),
Integer.toString(offset+UUID_LENGTH)));
Random r = (secure&&(secrand!=null))?secrand:rand;
nextBytes(into,offset,UUID_LENGTH,r);
into[6+offset] &= 0x0F;
into[6+offset] |= (UUID_VERSION << 4);
into[8+offset] &= 0x3F; //0011 1111
into[8+offset] |= 0x80; //1000 0000
return into;
}
/**
* Same as java.util.Random.nextBytes except this one we dont have to allocate a new byte array
* @param into byte[]
* @param offset int
* @param length int
* @param r Random
*/
public static void nextBytes(byte[] into, int offset, int length, Random r) {
int numRequested = length;
int numGot = 0, rnd = 0;
while (true) {
for (int i = 0; i < BYTES_PER_INT; i++) {
if (numGot == numRequested) return;
rnd = (i == 0 ? r.nextInt() : rnd >> BITS_PER_BYTE);
into[offset+numGot] = (byte) rnd;
numGot++;
}
}
}
}