001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.marshall.jena; 018 019 020import org.apache.juneau.commons.bean.*; 021import org.apache.juneau.commons.collections.*; 022import org.apache.juneau.marshall.*; 023import org.apache.juneau.marshall.parser.*; 024import org.apache.juneau.marshall.xml.*; 025import static org.apache.juneau.commons.utils.Shorts.*; 026 027/** 028 * Stream-based RDF parser for binary formats (RDF/THRIFT, RDF/PROTO). 029 * 030 * <p> 031 * Extends {@link InputStreamParser} and delegates RDF metadata to an internal {@link RdfParser}. 032 * 033 * <h5 class='section'>Notes:</h5><ul> 034 * <li class='note'>This class is thread safe and reusable. 035 * </ul> 036 * 037 * <h5 class='section'>See Also:</h5><ul> 038 * <li class='link'>{doc jmr.RdfDetails} 039 * </ul> 040 */ 041@SuppressWarnings({ 042 "java:S110", // Deep inheritance inherent to the RDF parser hierarchy. 043 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 044}) 045public class RdfStreamParser extends InputStreamParser implements RdfMetaProvider { 046 047 /** 048 * Builder class. 049 */ 050 @SuppressWarnings({ 051 "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name. 052 }) 053 public abstract static class Builder<SELF extends Builder<SELF>> extends InputStreamParser.Builder<SELF> { 054 055 private static final Cache<HashKey,RdfStreamParser> CACHE = Cache.of(HashKey.class, RdfStreamParser.class).build(); 056 057 private String language; 058 private RdfParser rdfParser; 059 060 /** 061 * Constructor, default settings. 062 */ 063 protected Builder() { 064 language = Constants.LANG_RDFTHRIFT; 065 } 066 067 /** 068 * Copy constructor. 069 * 070 * @param copyFrom The builder to copy from. 071 * <br>Cannot be <jk>null</jk>. 072 */ 073 protected Builder(Builder<?> copyFrom) { 074 super(reqnn("copyFrom", copyFrom)); 075 language = copyFrom.language; 076 rdfParser = copyFrom.rdfParser; 077 } 078 079 /** 080 * Copy constructor. 081 * 082 * @param copyFrom The bean to copy from. 083 * <br>Cannot be <jk>null</jk>. 084 */ 085 protected Builder(RdfStreamParser copyFrom) { 086 super(reqnn("copyFrom", copyFrom)); 087 language = copyFrom.language; 088 rdfParser = copyFrom.rdfParser; 089 } 090 091 /** 092 * RDF language (e.g. {@link Constants#LANG_RDFTHRIFT}, {@link Constants#LANG_RDFPROTO}). 093 * 094 * @param value The RDF language. 095 * @return This object. 096 */ 097 public SELF language(String value) { 098 language = value; 099 rdfParser = null; // Rebuild on next get 100 return self(); 101 } 102 103 @Override 104 public RdfStreamParser build() { 105 return cache(CACHE).build(RdfStreamParser.class); 106 } 107 108 @Override 109 public SELF consumes(String value) { 110 super.consumes(value); 111 return self(); 112 } 113 114 @Override /* Overridden from Context.Builder<?> */ 115 public abstract SELF copy(); 116 117 @Override 118 public HashKey hashKey() { 119 return HashKey.of(super.hashKey(), language); 120 } 121 122 RdfParser getRdfParser() { 123 if (rdfParser == null) 124 rdfParser = RdfParser.create().language(language).build(); 125 return rdfParser; 126 } 127 } 128 129 /** 130 * Concrete default builder leaf for the non-subclassed {@link RdfStreamParser#create()} / {@link RdfStreamParser#copy()} path. 131 */ 132 public static final class DefaultBuilder extends Builder<DefaultBuilder> { 133 134 DefaultBuilder() {} 135 136 DefaultBuilder(RdfStreamParser copyFrom) { 137 super(copyFrom); 138 } 139 140 DefaultBuilder(Builder<?> copyFrom) { 141 super(copyFrom); 142 } 143 144 @Override /* Overridden from Context.Builder<?> */ 145 public DefaultBuilder copy() { 146 return new DefaultBuilder(this); 147 } 148 } 149 150 /** 151 * Creates a new builder. 152 * 153 * @return A new builder. 154 */ 155 @SuppressWarnings({ 156 "java:S1452", // Builder<?> wildcard return intentional; callers chain via fluent API without needing the concrete type 157 "java:S9149" // Public Juneau DSL factory; hiding parent create() is intentional. 158 }) 159 public static Builder<?> create() { 160 return new DefaultBuilder(); 161 } 162 163 private final String language; 164 private final RdfParser rdfParser; 165 166 /** 167 * Constructor. 168 * 169 * @param builder The builder for this object. 170 * <br>Cannot be <jk>null</jk>. 171 */ 172 public RdfStreamParser(Builder<?> builder) { 173 super(reqnn("builder", builder).consumes(getConsumes(builder))); 174 language = builder.language; 175 rdfParser = builder.getRdfParser(); 176 } 177 178 private static String getConsumes(Builder<?> builder) { 179 if (builder.getConsumes() != null) 180 return builder.getConsumes(); 181 return switch (builder.language) { 182 case Constants.LANG_RDFTHRIFT -> "application/vnd.apache.thrift.binary"; 183 case Constants.LANG_RDFPROTO -> "application/vnd.apache.protobuf"; 184 default -> "application/octet-stream"; 185 }; 186 } 187 188 @Override 189 public Builder<?> copy() { 190 return new DefaultBuilder(this); 191 } 192 193 @Override 194 public RdfStreamParserSession.Builder createSession() { 195 return RdfStreamParserSession.create(this); 196 } 197 198 @Override 199 public RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) { 200 return rdfParser.getRdfBeanMeta(bm); 201 } 202 203 @Override 204 public RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) { 205 return rdfParser.getRdfBeanPropertyMeta(bpm); 206 } 207 208 @Override 209 public RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) { 210 return rdfParser.getRdfClassMeta(cm); 211 } 212 213 @Override 214 public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) { 215 return rdfParser.getXmlBeanMeta(bm); 216 } 217 218 @Override 219 public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) { 220 return rdfParser.getXmlBeanPropertyMeta(bpm); 221 } 222 223 @Override 224 public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) { 225 return rdfParser.getXmlClassMeta(cm); 226 } 227 228 /** 229 * Returns the RDF language. 230 * 231 * @return The RDF language. 232 */ 233 public String getLanguage() { 234 return language; 235 } 236 237 /** 238 * Returns the delegated RdfParser. 239 * 240 * @return The delegated RdfParser. 241 */ 242 protected RdfParser getRdfParser() { 243 return rdfParser; 244 } 245 246 /** Collection format - delegates to RdfParser. */ 247 protected RdfCollectionFormat getCollectionFormat() { 248 return rdfParser.getCollectionFormat(); 249 } 250 251 /** Juneau namespace - delegates to RdfParser. */ 252 protected Namespace getJuneauNs() { 253 return rdfParser.getJuneauNs(); 254 } 255 256 /** Juneau BP namespace - delegates to RdfParser. */ 257 protected Namespace getJuneauBpNs() { 258 return rdfParser.getJuneauBpNs(); 259 } 260 261 /** Loose collections - delegates to RdfParser. */ 262 protected boolean isLooseCollections() { 263 return rdfParser.isLooseCollections(); 264 } 265 266 /** Trim whitespace - delegates to RdfParser. */ 267 protected boolean isTrimWhitespace() { 268 return rdfParser.isTrimWhitespace(); 269 } 270}