Jak umieścić pakiet wiadomości JSF poza WAR?
dwa sposoby:
Add its path to the runtime classpath of the server.
Create a custom ResourceBundle
implementation with a Control
.
zmienić tekst i odświeżyć wiadomości w aplikacji bez konieczności ponownego uruchomienia aplikacji
zmieniając tekst będzie trywialne. Odświeżanie nie jest jednak trywialne. Mojarra wewnętrznie buforuje to agresywnie. Trzeba to wziąć pod uwagę na wypadek, gdybyś chciał pójść w drogę 1. Arjan Tijms opublikował specjalną sztuczkę Mojarra, aby wyczyścić pamięć podręczną wewnętrznego pakietu zasobów w tym pokrewnym pytaniu: How to reload resource bundle in web application?
Jeśli zmiana tekstu nastąpi w aplikacji webowej samodzielnie, możesz po prostu wykonać czyszczenie pamięci podręcznej w metodzie składowania. Jeśli zmiana tekstu może się jednak zdarzyć na zewnątrz, musisz zarejestrować file system watch service, aby nasłuchiwać zmian (tutorial here), a następnie albo dla sposobu 1 wyczyścić pamięć podręczną pakunku, albo dla sposobu 2 przeładować wewnętrznie w handleGetObject()
.
mieć domyślny pakiet w wojnie, która jest zastąpione przez wiązki zewnętrznej
Wkładając je ze ścieżki klasy, domyślne zachowanie jest na odwrót (zasoby na wojnie mają wyższy priorytet ładowania klas), więc to zdecydowanie zadrapuje 1 i zostawia nas na drodze 2.
Poniżej znajduje się przykład kickoff z drogi 2. Zakłada się, że używasz koksu zasobów nieruchomości dles o nazwie bazowej text
(tj. bez pakietu) i że ścieżka zewnętrzna znajduje się w /var/webapp/i18n
.
public class YourBundle extends ResourceBundle {
protected static final Path EXTERNAL_PATH = Paths.get("/var/webapp/i18n");
protected static final String BASE_NAME = "text";
protected static final Control CONTROL = new YourControl();
private static final WatchKey watcher;
static {
try {
watcher = EXTERNAL_PATH.register(FileSystems.getDefault().newWatchService(), StandardWatchEventKinds.ENTRY_MODIFY);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
private Path externalResource;
private Properties properties;
public YourBundle() {
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
setParent(ResourceBundle.getBundle(BASE_NAME, locale, CONTROL));
}
private YourBundle(Path externalResource, Properties properties) {
this.externalResource = externalResource;
this.properties = properties;
}
@Override
protected Object handleGetObject(String key) {
if (properties != null) {
if (!watcher.pollEvents().isEmpty()) { // TODO: this is naive, you'd better check resource name if you've multiple files in the folder and keep track of others.
synchronized(properties) {
try (InputStream input = new FileInputStream(externalResource.toFile())) {
properties.load(input);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
return properties.get(key);
}
return parent.getObject(key);
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public Enumeration<String> getKeys() {
if (properties != null) {
Set keys = properties.keySet();
return Collections.enumeration(keys);
}
return parent.getKeys();
}
protected static class YourControl extends Control {
@Override
public ResourceBundle newBundle
(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException
{
String resourceName = toResourceName(toBundleName(baseName, locale), "properties");
Path externalResource = EXTERNAL_PATH.resolve(resourceName);
Properties properties = new Properties();
try (InputStream input = loader.getResourceAsStream(resourceName)) {
properties.load(input); // Default (internal) bundle.
}
try (InputStream input = new FileInputStream(externalResource.toFile())) {
properties.load(input); // External bundle (will overwrite same keys).
}
return new YourBundle(externalResource, properties);
}
}
}
Aby uruchomić, należy zarejestrować się poniżej w pozycji faces-config.xml
.
<application>
<resource-bundle>
<base-name>com.example.YourBundle</base-name>
<var>i18n</var>
</resource-bundle>
</application>
Czy to pomocne? http://stackoverflow.com/q/4499732 – BalusC
@BalusC Cóż, nie przyjrzeliśmy się szczegółom tego pytania, gdy natknęliśmy się na niego wcześniej, ponieważ odnosi się ono do obsługi przez bazę danych, której nie mam tutaj - ale domyślam się masz na myśli część rozszerzenia 'ResourceBundle'? Więc w części 'getItSomehow' należy ją załadować poprzez operację na plikach? W takim przypadku może to być sposób na poradzenie sobie z tym. Tylko te dwa opcjonalne wymagania nie są tutaj jasne. –
@BalusC Ok, 2) ma sens, 1) może jest źle zrozumiany - nie muszę odzwierciedlać zmian z powrotem do pliku, ale być w stanie zmienić plik, a następnie uruchomić przeładowanie pakietu. - Jeśli chcesz spędzić czas, aby umieścić komentarze w odpowiedzi, z przyjemnością przypiszę nagrodę. –