Java tutorial
/* * Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team * * Licensed 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.b3log.latke.repository; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.b3log.latke.Latkes; import org.b3log.latke.repository.impl.UserRepositoryImpl; import org.b3log.latke.util.CollectionUtils; import org.b3log.latke.util.Strings; import org.json.JSONArray; import org.json.JSONObject; /** * Repository utilities. * * @author <a href="mailto:DL88250@gmail.com">Liang Ding</a> * @version 1.0.0.8, Oct 18, 2012 */ public final class Repositories { /** * Logger. */ private static final Logger LOGGER = Logger.getLogger(Repositories.class.getName()); /** * Repository holder. * * <p> * <repositoryName, {@link Repository repository}> * <p> */ private static final Map<String, Repository> REPOS_HOLDER = new ConcurrentHashMap<String, Repository>(); /** * Repositories description (repository.json). */ private static JSONObject repositoriesDescription; /** * Whether all repositories is writable. */ private static boolean repositoryiesWritable = true; /** * Whether all repositories is writable. * * @return {@code true} if they are writable, returns {@code false} otherwise */ public static boolean getReposirotiesWritable() { return repositoryiesWritable; } /** * Sets all repositories whether is writable with the specified flag. * * @param writable the specified flat, {@code true} for writable, {@code false} otherwise */ public static void setRepositoriesWritable(final boolean writable) { for (final Map.Entry<String, Repository> entry : REPOS_HOLDER.entrySet()) { final String repositoryName = entry.getKey(); final Repository repository = entry.getValue(); repository.setWritable(writable); LOGGER.log(Level.INFO, "Sets repository[name={0}] writable[{1}]", new Object[] { repositoryName, writable }); } repositoryiesWritable = writable; } /** * Gets repository names. * * @return repository names, for example, * <pre> * [ * "repository1", "repository2", .... * ] * </pre> */ public static JSONArray getRepositoryNames() { final JSONArray ret = new JSONArray(); if (null == repositoriesDescription) { LOGGER.log(Level.INFO, "Not found repository description[repository.json] file under classpath"); return ret; } final JSONArray repositories = repositoriesDescription.optJSONArray("repositories"); for (int i = 0; i < repositories.length(); i++) { final JSONObject repository = repositories.optJSONObject(i); ret.put(repository.optString("name")); } return ret; } /** * Gets repositories description. * * @return repositories description, returns {@code null} if not found or * parse the description failed */ public static JSONObject getRepositoriesDescription() { return repositoriesDescription; } static { // Initializes the Latke built-in user repository. addRepository(UserRepositoryImpl.getInstance()); loadRepositoryDescription(); } /** * Determines whether the specified json object can not be * persisted (add or update) into an repository which specified by * the given repository name. * * <p> * A valid json object to persist must match keys definitions * (including type and length if had) in the repository * description (repository.json) with the json object names itself. * </p> * * <p> * The specified keys to ignore will be bypassed, regardless of matching * keys definitions. * </p> * * @param repositoryName the given repository name * @param jsonObject the specified json object * @param ignoredKeys the specified keys to ignore * @throws RepositoryException if the specified json object can not be * persisted * @see Repository#add(org.json.JSONObject) * @see Repository#update(java.lang.String, org.json.JSONObject) */ public static void check(final String repositoryName, final JSONObject jsonObject, final String... ignoredKeys) throws RepositoryException { if (null == jsonObject) { throw new RepositoryException("Null to persist to repository[" + repositoryName + "]"); } final boolean needIgnoreKeys = null != ignoredKeys && 0 < ignoredKeys.length; final JSONArray names = jsonObject.names(); final Set<Object> nameSet = CollectionUtils.jsonArrayToSet(names); final JSONArray keysDescription = getRepositoryKeysDescription(repositoryName); if (null == keysDescription) { // Not found repository description // Skips the checks return; } final Set<String> keySet = new HashSet<String>(); // Checks whether the specified json object has all keys defined, // and whether the type of its value is appropriate for (int i = 0; i < keysDescription.length(); i++) { final JSONObject keyDescription = keysDescription.optJSONObject(i); final String key = keyDescription.optString("name"); keySet.add(key); if (needIgnoreKeys && Strings.contains(key, ignoredKeys)) { continue; } if (!keyDescription.optBoolean("nullable") && !nameSet.contains(key)) { throw new RepositoryException("A json object to persist to repository[name=" + repositoryName + "] does not contain a key[" + key + "]"); } // TODO: 88250, type and length validation /* * final String type = keyDescription.optString("type"); final * Object value = jsonObject.opt(key); * * if (("String".equals(type) && !(value instanceof String)) || * ("int".equals(type) && !(value instanceof Integer)) || * ("long".equals(type) && !(value instanceof Long)) || * ("double".equals(type) && !(value instanceof Double)) || * ("boolean".equals(type) && !(value instanceof Boolean))) { * LOGGER.log(Level.WARNING, * "A json object to persist to repository[name={0}] has " + * "a wrong value type[definedType={1}, currentType={2}] with key[" * + key + "]", new Object[]{repositoryName, type, * value.getClass()}); * * return true; } */ } // Checks whether the specified json object has an redundant (undefined) key for (int i = 0; i < names.length(); i++) { final String name = names.optString(i); if (!keySet.contains(name)) { throw new RepositoryException("A json object to persist to repository[name=" + repositoryName + "] contains an redundant key[" + name + "]"); } } } /** * Gets the keys description of an repository specified by the given repository name. * * @param repositoryName the given repository name * @return keys description, returns {@code null} if not found */ public static JSONArray getRepositoryKeysDescription(final String repositoryName) { if (Strings.isEmptyOrNull(repositoryName)) { return null; } if (null == repositoriesDescription) { return null; } final JSONArray repositories = repositoriesDescription.optJSONArray("repositories"); for (int i = 0; i < repositories.length(); i++) { final JSONObject repository = repositories.optJSONObject(i); if (repositoryName.equals(repository.optString("name"))) { return repository.optJSONArray("keys"); } } throw new RuntimeException("Not found the repository[name=" + repositoryName + "] description, please define it in repositories.json"); } /** * Gets the key names of an repository specified by the given repository name. * * @param repositoryName the given repository name * @return a set of key names, returns an empty set if not found */ public static Set<String> getKeyNames(final String repositoryName) { if (Strings.isEmptyOrNull(repositoryName)) { return Collections.emptySet(); } if (null == repositoriesDescription) { return null; } final JSONArray repositories = repositoriesDescription.optJSONArray("repositories"); JSONArray keys = null; for (int i = 0; i < repositories.length(); i++) { final JSONObject repository = repositories.optJSONObject(i); if (repositoryName.equals(repository.optString("name"))) { keys = repository.optJSONArray("keys"); } } if (null == keys) { throw new RuntimeException("Not found the repository[name=" + repositoryName + "] description, please define it in repositories.json"); } final Set<String> ret = new HashSet<String>(); for (int i = 0; i < keys.length(); i++) { final JSONObject keyDescription = keys.optJSONObject(i); final String key = keyDescription.optString("name"); ret.add(key); } return ret; } /** * Gets a repository with the specified repository name. * * @param repositoryName the specified repository name * @return repository, returns {@code null} if not found */ public static Repository getRepository(final String repositoryName) { return REPOS_HOLDER.get(repositoryName); } /** * Adds the specified repository. * * @param repository the specified repository */ public static void addRepository(final Repository repository) { REPOS_HOLDER.put(repository.getName(), repository); } /** * Loads repository description. */ private static void loadRepositoryDescription() { LOGGER.log(Level.INFO, "Loading repository description...."); final InputStream inputStream = AbstractRepository.class.getClassLoader() .getResourceAsStream("repository.json"); if (null == inputStream) { LOGGER.log(Level.INFO, "Not found repository description[repository.json] file under classpath"); return; } LOGGER.log(Level.INFO, "Parsing repository description...."); try { final String description = IOUtils.toString(inputStream); LOGGER.log(Level.CONFIG, "{0}{1}", new Object[] { Strings.LINE_SEPARATOR, description }); repositoriesDescription = new JSONObject(description); // Repository name prefix final String tableNamePrefix = StringUtils.isNotBlank(Latkes.getLocalProperty("jdbc.tablePrefix")) ? Latkes.getLocalProperty("jdbc.tablePrefix") + "_" : ""; final JSONArray repositories = repositoriesDescription.optJSONArray("repositories"); for (int i = 0; i < repositories.length(); i++) { final JSONObject repository = repositories.optJSONObject(i); repository.put("name", tableNamePrefix + repository.optString("name")); } } catch (final Exception e) { LOGGER.log(Level.SEVERE, "Parses repository description failed", e); } finally { try { inputStream.close(); } catch (final IOException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); throw new RuntimeException(e); } } } /** * Private constructor. */ private Repositories() { } }