/* * Copyright 2010 Outerthought bvba * * 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.lilyproject.linkindex; import java.util.List; import java.util.Map; import org.lilyproject.repository.api.FieldType; import org.lilyproject.repository.api.FieldTypeNotFoundException; import org.lilyproject.repository.api.IdRecord; import org.lilyproject.repository.api.LRepository; import org.lilyproject.repository.api.Link; import org.lilyproject.repository.api.QName; import org.lilyproject.repository.api.Record; import org.lilyproject.repository.api.RecordId; import org.lilyproject.repository.api.RepositoryException; import org.lilyproject.repository.api.RepositoryManager; import org.lilyproject.repository.api.SchemaId; import org.lilyproject.repository.api.TypeManager; import org.lilyproject.repository.api.ValueType; public class RecordLinkExtractor { private RecordLinkExtractor() { } /** * Extracts the links from a record. The provided Record object should * be "fully loaded" (= contain all fields). */ public static void extract(IdRecord record, LinkCollector collector, LRepository repository) throws RepositoryException, InterruptedException { for (Map.Entry<SchemaId, Object> field : record.getFieldsById().entrySet()) { FieldType fieldType; try { fieldType = repository.getTypeManager().getFieldTypeById(field.getKey()); } catch (FieldTypeNotFoundException e) { // Can not do anything with a field if we cannot load its type continue; } extract(field.getValue(), fieldType, collector, fieldType, record.getId(), repository); } } /** * This is for link extraction from nested records. */ private static void extractRecord(Record record, LinkCollector collector, FieldType ctxField, RecordId ctxRecord, LRepository repository) throws RepositoryException, InterruptedException { for (Map.Entry<QName, Object> field : record.getFields().entrySet()) { FieldType fieldType; try { fieldType = repository.getTypeManager().getFieldTypeByName(field.getKey()); } catch (FieldTypeNotFoundException e) { // Can not do anything with a field if we cannot load its type continue; } // The ctxField and ctxRecord need to stay the top-level ones! It does not matter how // deeply nested a link occurs, as far as the link index is concerned, it still occurs // with the field of the top level record. extract(field.getValue(), fieldType, collector, ctxField, ctxRecord, repository); } } private static void extract(Object value, FieldType fieldType, LinkCollector collector, FieldType ctxField, RecordId ctxRecord, LRepository repository) throws RepositoryException, InterruptedException { ValueType valueType = fieldType.getValueType(); String baseType = valueType.getDeepestValueType().getBaseName(); if (baseType.equals("LINK") || baseType.equals("RECORD")) { extract(value, collector, ctxField, ctxRecord, repository); } } private static void extract(Object value, LinkCollector collector, FieldType ctxField, RecordId ctxRecord, LRepository repository) throws RepositoryException, InterruptedException { if (value instanceof List) { List list = (List)value; for (Object item : list) { extract(item, collector, ctxField, ctxRecord, repository); } } else if (value instanceof Record) { extractRecord((Record)value, collector, ctxField, ctxRecord, repository); } else if (value instanceof Link) { RecordId recordId = ((Link)value).resolve(ctxRecord, repository.getIdGenerator()); collector.addLink(recordId, ctxField.getId()); } else { throw new RuntimeException("Encountered an unexpected kind of object from a link field: " + value.getClass().getName()); } } }