/* | |
* 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.openmeetings.db.dao.label; | |
import static org.apache.openmeetings.db.util.ApplicationHelper.ensureApplication; | |
import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.InvalidPropertiesFormatException; | |
import java.util.Iterator; | |
import java.util.LinkedHashMap; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.Properties; | |
import java.util.Set; | |
import java.util.concurrent.ConcurrentHashMap; | |
import org.apache.commons.collections4.CollectionUtils; | |
import org.apache.commons.collections4.Predicate; | |
import org.apache.openmeetings.db.dao.IDataProviderDao; | |
import org.apache.openmeetings.db.entity.label.StringLabel; | |
import org.apache.openmeetings.util.OmFileHelper; | |
import org.apache.openmeetings.util.XmlExport; | |
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; | |
import org.apache.wicket.util.string.Strings; | |
import org.dom4j.Document; | |
import org.dom4j.Element; | |
import org.dom4j.io.SAXReader; | |
import org.red5.logging.Red5LoggerFactory; | |
import org.slf4j.Logger; | |
/** | |
* | |
* CRUD operations for {@link StringLabel} | |
* | |
* @author solomax, swagner | |
* | |
*/ | |
public class LabelDao implements IDataProviderDao<StringLabel>{ | |
private static final Logger log = Red5LoggerFactory.getLogger(LabelDao.class, webAppRootKey); | |
private static final String ENTRY_ELEMENT = "entry"; | |
private static final String KEY_ATTR = "key"; | |
public static final String APP_RESOURCES_EN = "Application.properties.xml"; | |
public static final String APP_RESOURCES = "Application_%s.properties.xml"; | |
public static final LinkedHashMap<Long, Locale> languages = new LinkedHashMap<>(); //TODO hide it and return unmodifiable map | |
public static final ConcurrentHashMap<Locale, List<StringLabel>> labelCache = new ConcurrentHashMap<>(); | |
public static final Set<String> keys = new HashSet<>(); | |
private static Class<?> APP = null; | |
public List<Map<String, Object>> getStrings(Long language_id, int start, int count) { | |
List<Map<String, Object>> result = new ArrayList<>(); | |
for (int i = 0; i < count; ++i) { | |
Map<String, Object> map = new HashMap<>(); | |
map.put("id", start + i); | |
map.put("value", getString(start + i, language_id)); | |
result.add(map); | |
} | |
return result; | |
} | |
private static void storeLanguages() throws Exception { | |
Document d = XmlExport.createDocument(); | |
Element r = XmlExport.createRoot(d, "language"); | |
for (Map.Entry<Long, Locale> e : languages.entrySet()) { | |
r.addElement("lang").addAttribute("id", "" + e.getKey()).addAttribute("code", e.getValue().toLanguageTag()); | |
} | |
XmlExport.toXml(getLangFile(), d); | |
} | |
public static void add(Locale l) throws Exception { | |
long id = 0L; | |
for (Map.Entry<Long, Locale> e : languages.entrySet()) { | |
id = e.getKey(); | |
} | |
languages.put(id + 1, l); | |
storeLanguages(); | |
labelCache.put(l, new ArrayList<StringLabel>()); | |
} | |
public String getString(long fieldValuesId, long langId) { | |
return ensureApplication(langId).getOmString(fieldValuesId, langId); | |
} | |
public String getString(String key, long langId) { | |
return ensureApplication(langId).getOmString(key, langId); | |
} | |
private static File getLangFile() { | |
return new File(OmFileHelper.getLanguagesDir(), OmFileHelper.nameOfLanguageFile); | |
} | |
public static synchronized Class<?> getAppClass() throws ClassNotFoundException { | |
if (APP == null) { | |
//FIXME HACK to resolve package dependencies | |
APP = Class.forName("org.apache.openmeetings.web.app.Application"); | |
} | |
return APP; | |
} | |
public static void initLanguageMap() { | |
SAXReader reader = new SAXReader(); | |
try { | |
getAppClass(); | |
Document document = reader.read(getLangFile()); | |
Element root = document.getRootElement(); | |
languages.clear(); | |
for (@SuppressWarnings("unchecked")Iterator<Element> it = root.elementIterator("lang"); it.hasNext();) { | |
Element item = it.next(); | |
Long id = Long.valueOf(item.attributeValue("id")); | |
String code = item.attributeValue("code"); | |
if (id == 3L) { | |
continue; | |
} | |
languages.put(id, Locale.forLanguageTag(code)); | |
} | |
} catch (Exception e) { | |
log.error("Error while building language map"); | |
} | |
} | |
public static String getLabelFileName(Locale l) { | |
String name = APP_RESOURCES_EN; | |
if (!Locale.ENGLISH.equals(l)) { | |
name = String.format(APP_RESOURCES, l.toLanguageTag().replace('-', '_')); | |
} | |
return name; | |
} | |
private static void storeLabels(Locale l) throws Exception { | |
Document d = XmlExport.createDocument(); | |
Element r = XmlExport.createRoot(d); | |
List<StringLabel> labels = labelCache.get(l); | |
for (StringLabel sl : labels) { | |
r.addElement(ENTRY_ELEMENT).addAttribute(KEY_ATTR, sl.getKey()).addCDATA(sl.getValue()); | |
} | |
URL u = APP.getResource(getLabelFileName(l)); | |
XmlExport.toXml(new File(u.toURI()), d); | |
} | |
public static void upload(Locale l, InputStream is) throws Exception { | |
List<StringLabel> labels = getLabels(is); | |
URL u = APP.getResource(getLabelFileName(Locale.ENGLISH)); //get the URL of existing resource | |
File el = new File(u.toURI()); | |
File f = new File(el.getParentFile(), getLabelFileName(l)); | |
if (!f.exists()) { | |
f.createNewFile(); | |
} | |
labelCache.put(l, labels); | |
storeLabels(l); | |
} | |
private static List<StringLabel> getLabels(Locale l) { | |
List<StringLabel> labels = new ArrayList<>(); | |
try (InputStream is = APP.getResourceAsStream(getLabelFileName(l))) { | |
labels = getLabels(is); | |
} catch (Exception e) { | |
log.error("Error reading resources document", e); | |
} | |
return labels; | |
} | |
private static List<StringLabel> getLabels(InputStream is) throws InvalidPropertiesFormatException, IOException { | |
final List<StringLabel> labels = new ArrayList<>(); | |
Properties props = new Properties(); | |
props.loadFromXML(is); | |
props.forEach((k, v) -> labels.add(new StringLabel((String)k, (String)v))); | |
return labels; | |
} | |
private static List<StringLabel> getLabels(Locale l, final String search) { | |
if (!labelCache.containsKey(l)) { | |
List<StringLabel> ll = getLabels(l); | |
if (ll != null) { | |
labelCache.putIfAbsent(l, ll); | |
} | |
} | |
List<StringLabel> result = new ArrayList<>(labelCache.containsKey(l) ? labelCache.get(l) : new ArrayList<StringLabel>()); | |
if (!Strings.isEmpty(search)) { | |
CollectionUtils.filter(result, new Predicate<StringLabel>() { | |
@Override | |
public boolean evaluate(StringLabel o) { | |
return o != null && (o.getKey().contains(search) || o.getValue().contains(search)); | |
} | |
}); | |
} | |
return result; | |
} | |
@Override | |
public StringLabel get(long id) { | |
throw new RuntimeException("Should not be used"); | |
} | |
@Override | |
public StringLabel get(Long id) { | |
throw new RuntimeException("Should not be used"); | |
} | |
@Override | |
public List<StringLabel> get(int start, int count) { | |
throw new RuntimeException("Should not be used"); | |
} | |
@Override | |
public List<StringLabel> get(String search, int start, int count, String order) { | |
throw new RuntimeException("Should not be used"); | |
} | |
public List<StringLabel> get(Locale l, final String search, int start, int count, final SortParam<String> sort) { | |
List<StringLabel> result = getLabels(l, search); | |
if (sort != null) { | |
Collections.sort(result, new Comparator<StringLabel>() { | |
@Override | |
public int compare(StringLabel o1, StringLabel o2) { | |
int val = 0; | |
if (KEY_ATTR.equals(sort.getProperty())) { | |
try { | |
int i1 = Integer.parseInt(o1.getKey()), i2 = Integer.parseInt(o2.getKey()); | |
val = i1 - i2; | |
} catch (Exception e) { | |
val = o1.getKey().compareTo(o2.getKey()); | |
} | |
} else { | |
val = o1.getValue().compareTo(o2.getValue()); | |
} | |
return (sort.isAscending() ? 1 : -1) * val; | |
} | |
}); | |
} | |
return result.subList(start, start + count > result.size() ? result.size() : start + count); | |
} | |
@Override | |
public long count() { | |
throw new RuntimeException("Should not be used"); | |
} | |
@Override | |
public long count(String search) { | |
throw new RuntimeException("Should not be used"); | |
} | |
public long count(Locale l, final String search) { | |
return getLabels(l, search).size(); | |
} | |
@Override | |
public StringLabel update(StringLabel entity, Long userId) { | |
throw new RuntimeException("Should not be used"); | |
} | |
public StringLabel update(Locale l, StringLabel entity) throws Exception { | |
List<StringLabel> labels = labelCache.get(l); | |
if (!labels.contains(entity)) { | |
labels.add(entity); | |
keys.add(entity.getKey()); | |
} | |
storeLabels(l); | |
return entity; | |
} | |
@Override | |
public void delete(StringLabel entity, Long userId) { | |
throw new RuntimeException("Should not be used"); | |
} | |
public void delete(Locale l, StringLabel entity) throws Exception { | |
List<StringLabel> labels = labelCache.get(l); | |
if (labels.contains(entity)) { | |
labels.remove(entity); | |
keys.remove(entity.getKey()); | |
storeLabels(l); | |
} | |
} | |
public static void delete(Locale l) { | |
for (Map.Entry<Long, Locale> e : languages.entrySet()) { | |
if (e.getValue().equals(l)) { | |
languages.remove(e.getKey()); | |
break; | |
} | |
} | |
labelCache.remove(l); | |
try { | |
URL u = APP.getResource(getLabelFileName(l)); | |
if (u != null) { | |
File f = new File(u.toURI()); | |
if (f.exists()) { | |
f.delete(); | |
} | |
} | |
} catch (Exception e) { | |
log.error("Unexpected error while deleting language", e); | |
} | |
} | |
} |