blob: 6ef771302e6a326747861501e4113d313bbac6a2 [file] [log] [blame]
/*
* 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.ignite.internal;
import org.apache.ignite.*;
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.*;
import org.apache.ignite.internal.util.typedef.internal.*;
import org.apache.ignite.marshaller.*;
import org.apache.ignite.plugin.*;
import org.jetbrains.annotations.*;
import org.jsr166.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
/**
* Marshaller context adapter.
*/
public abstract class MarshallerContextAdapter implements MarshallerContext {
/** */
private static final String CLS_NAMES_FILE = "META-INF/classnames.properties";
/** */
private static final String JDK_CLS_NAMES_FILE = "META-INF/classnames-jdk.properties";
/** */
private final ConcurrentMap<Integer, String> map = new ConcurrentHashMap8<>();
/** */
private final Set<String> registeredSystemTypes = new HashSet<>();
/**
* Initializes context.
*
* @param plugins Plugins.
*/
public MarshallerContextAdapter(@Nullable List<PluginProvider> plugins) {
try {
ClassLoader ldr = U.gridClassLoader();
Enumeration<URL> urls = ldr.getResources(CLS_NAMES_FILE);
boolean foundClsNames = false;
while (urls.hasMoreElements()) {
processResource(urls.nextElement());
foundClsNames = true;
}
if (!foundClsNames)
throw new IgniteException("Failed to load class names properties file packaged with ignite binaries " +
"[file=" + CLS_NAMES_FILE + ", ldr=" + ldr + ']');
URL jdkClsNames = ldr.getResource(JDK_CLS_NAMES_FILE);
if (jdkClsNames == null)
throw new IgniteException("Failed to load class names properties file packaged with ignite binaries " +
"[file=" + JDK_CLS_NAMES_FILE + ", ldr=" + ldr + ']');
processResource(jdkClsNames);
checkHasClassName(GridDhtPartitionFullMap.class.getName(), ldr, CLS_NAMES_FILE);
checkHasClassName(GridDhtPartitionMap.class.getName(), ldr, CLS_NAMES_FILE);
checkHasClassName(HashMap.class.getName(), ldr, JDK_CLS_NAMES_FILE);
if (plugins != null && !plugins.isEmpty()) {
for (PluginProvider plugin : plugins) {
URL pluginClsNames = ldr.getResource("META-INF/" + plugin.name().toLowerCase()
+ ".classnames.properties");
if (pluginClsNames != null)
processResource(pluginClsNames);
}
}
}
catch (IOException e) {
throw new IllegalStateException("Failed to initialize marshaller context.", e);
}
}
/**
* @param clsName Class name.
* @param ldr Class loader used to get properties file.
* @param fileName File name.
*/
public void checkHasClassName(String clsName, ClassLoader ldr, String fileName) {
if (!map.containsKey(clsName.hashCode()))
throw new IgniteException("Failed to read class name from class names properties file. " +
"Make sure class names properties file packaged with ignite binaries is not corrupted " +
"[clsName=" + clsName + ", fileName=" + fileName + ", ldr=" + ldr + ']');
}
/**
* @param url Resource URL.
* @throws IOException In case of error.
*/
private void processResource(URL url) throws IOException {
try (InputStream in = url.openStream()) {
BufferedReader rdr = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = rdr.readLine()) != null) {
if (line.isEmpty() || line.startsWith("#"))
continue;
String clsName = line.trim();
int typeId = clsName.hashCode();
String oldClsName;
if ((oldClsName = map.put(typeId, clsName)) != null) {
if (!oldClsName.equals(clsName))
throw new IgniteException("Duplicate type ID [id=" + typeId + ", clsName=" + clsName +
", oldClsName=" + oldClsName + ']');
}
registeredSystemTypes.add(clsName);
}
}
}
/** {@inheritDoc} */
@Override public boolean registerClass(int id, Class cls) throws IgniteCheckedException {
boolean registered = true;
String clsName = map.get(id);
if (clsName == null) {
registered = registerClassName(id, cls.getName());
if (registered)
map.putIfAbsent(id, cls.getName());
}
else if (!clsName.equals(cls.getName()))
throw new IgniteCheckedException("Duplicate ID [id=" + id + ", oldCls=" + clsName +
", newCls=" + cls.getName());
return registered;
}
/** {@inheritDoc} */
@Override public Class getClass(int id, ClassLoader ldr) throws ClassNotFoundException, IgniteCheckedException {
String clsName = map.get(id);
if (clsName == null) {
clsName = className(id);
if (clsName == null)
throw new ClassNotFoundException("Unknown type ID: " + id);
String old = map.putIfAbsent(id, clsName);
if (old != null)
clsName = old;
}
return U.forName(clsName, ldr);
}
/** {@inheritDoc} */
@Override public boolean isSystemType(String typeName) {
return registeredSystemTypes.contains(typeName);
}
/**
* Registers class name.
*
* @param id Type ID.
* @param clsName Class name.
* @return Whether class name was registered.
* @throws IgniteCheckedException In case of error.
*/
protected abstract boolean registerClassName(int id, String clsName) throws IgniteCheckedException;
/**
* Gets class name by type ID.
*
* @param id Type ID.
* @return Class name.
* @throws IgniteCheckedException In case of error.
*/
protected abstract String className(int id) throws IgniteCheckedException;
}