blob: 6d2c47b69cb46ee0a0bf6143397d6f07ae580d00 [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.logging.log4j.audit.catalog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.audit.exception.AuditException;
import org.apache.logging.log4j.audit.util.NamingUtils;
import org.apache.logging.log4j.catalog.api.Attribute;
import org.apache.logging.log4j.catalog.api.CatalogData;
import org.apache.logging.log4j.catalog.api.CatalogReader;
import org.apache.logging.log4j.catalog.api.Event;
import org.apache.logging.log4j.catalog.api.EventAttribute;
import static java.util.Collections.emptyList;
import static org.apache.logging.log4j.catalog.api.constant.Constants.DEFAULT_CATALOG;
/**
*
*/
public class CatalogManagerImpl implements CatalogManager {
private static final Logger logger = LogManager.getLogger(CatalogManagerImpl.class);
private volatile Map<String, Map<String, CatalogInfo>> infoMap;
private final Map<String, Attribute> requestContextAttributes = new HashMap<>();
protected final Map<String, Map<String, Attribute>> attributeMap = new ConcurrentHashMap<>();
private static final String REQCTX = "ReqCtx_";
protected CatalogData catalogData;
public CatalogManagerImpl(CatalogReader catalogReader) {
try {
infoMap = initializeData(catalogReader);
} catch (Exception ex) {
throw new AuditException("Unable to initialize catalog data", ex);
}
}
protected Map<String, Map<String, CatalogInfo>> getInfoMap() {
return infoMap;
}
@Override
public Event getEvent(String eventName, String catalogId) {
CatalogInfo info = getCatalogInfo(eventName, catalogId);
return info != null ? info.event : null;
}
@Override
public List<String> getRequiredContextAttributes(String eventName, String catalogId) {
Map<String, CatalogInfo> catalogMap = infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId);
return catalogMap != null ? catalogMap.get(eventName).requiredContextAttributes : null;
}
@Override
public Map<String, Attribute> getAttributes(String eventName, String catalogId) {
Event event = getEvent(eventName, catalogId);
if (event == null) {
logger.warn("The event named {} could not be found in catalog {}", eventName, catalogId);
return null;
}
List<EventAttribute> eventAttributes = event.getAttributes() == null ? emptyList() : event.getAttributes();
Map<String, Attribute> attributes = new HashMap<>(eventAttributes.size());
for (EventAttribute eventAttribute : eventAttributes) {
Attribute attr = getAttribute(eventAttribute.getName(), event.getCatalogId());
if (attr != null) {
attributes.put(attr.getName(), attr);
}
}
return attributes;
}
@Override
public List<String> getAttributeNames(String eventName, String catalogId) {
return infoMap.get(catalogId == null ? DEFAULT_CATALOG : catalogId).get(eventName).attributeNames;
}
@Override
public Attribute getAttribute(String name) {
Map<String, Attribute> attrMap = attributeMap.get(DEFAULT_CATALOG);
return attrMap != null ? attrMap.get(name) : null;
}
public Attribute getAttribute(String name, String catalogId) {
Map<String, Attribute> attrMap = attributeMap.get(catalogId);
if (attrMap == null || !attrMap.containsKey(name)) {
attrMap = attributeMap.get(DEFAULT_CATALOG);
}
return attrMap != null ? attrMap.get(name) : null;
}
@Override
public Map<String, Attribute> getRequestContextAttributes() {
return requestContextAttributes;
}
private CatalogInfo getCatalogInfo(String eventName, String catalogId) {
Map<String, CatalogInfo> defaultCatalog = infoMap.get(DEFAULT_CATALOG);
Map<String, CatalogInfo> catalog = catalogId != null ? infoMap.get(catalogId) : null;
return catalog != null && catalog.containsKey(eventName) ? catalog.get(eventName) :
defaultCatalog.get(eventName);
}
private Map<String, Map<String, CatalogInfo>> initializeData(CatalogReader catalogReader) throws Exception {
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
ObjectMapper mapper = new ObjectMapper(factory);
String catalog = catalogReader.readCatalog();
catalogData = mapper.readValue(catalog, CatalogData.class);
if (catalogData.getAttributes() != null) {
for (Attribute attr : catalogData.getAttributes()) {
if (attr.isRequestContext()) {
requestContextAttributes.put(attr.getName(), attr);
}
Map<String, Attribute> attrMap = attributeMap.computeIfAbsent(attr.getCatalogId(), k -> new HashMap<>());
attrMap.put(attr.getName(), attr);
}
}
Map<String, Map<String, CatalogInfo>> map = new HashMap<>();
map.put(DEFAULT_CATALOG, new HashMap<>());
for (Event event : catalogData.getEvents()) {
addEntry(map, event);
}
return map;
}
protected void addEntry(Map<String, Map<String, CatalogInfo>> map, Event event) {
CatalogInfo info = new CatalogInfo();
info.event = event;
String catalogId = event.getCatalogId();
if (catalogId != null && catalogId.length() > 0 && !map.containsKey(catalogId)) {
map.put(catalogId, new HashMap<>());
}
List<String> required = new ArrayList<>();
List<String> names = new ArrayList<>();
info.attributes = new HashMap<>(names.size());
if (event.getAttributes() != null) {
for (EventAttribute eventAttribute : event.getAttributes()) {
String name = eventAttribute.getName();
Attribute attribute = getAttribute(name, event.getCatalogId());
if (attribute != null) {
info.attributes.put(name, attribute);
if (name.indexOf('.') != -1) {
name = name.replaceAll("\\.", "");
}
if (name.indexOf('/') != -1) {
name = name.replaceAll("/", "");
}
if (attribute.isRequestContext()) {
if (attribute.isRequired()) {
if (name.startsWith(REQCTX)) {
name = name.substring(REQCTX.length());
}
required.add(name);
}
} else {
names.add(name);
}
} else {
throw new IllegalStateException("Attribute " + name + " is not defined");
}
}
}
info.requiredContextAttributes = required;
info.attributeNames = names;
Map<String, CatalogInfo> catalogMap = catalogId == null ?
map.get(DEFAULT_CATALOG) : map.get(catalogId);
catalogMap.put(NamingUtils.getFieldName(event.getName()), info);
}
protected class CatalogInfo {
private Event event;
private List<String> requiredContextAttributes;
private List<String> attributeNames;
private Map<String, Attribute> attributes;
}
}