Java tutorial
/** * personium.io * Copyright 2014 FUJITSU LIMITED * * 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 io.personium.core.rs.odata; import java.io.Reader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.UriInfo; import org.apache.http.HttpStatus; import org.odata4j.core.NamedValue; import org.odata4j.core.NamespacedAnnotation; import org.odata4j.core.OCollection; import org.odata4j.core.OCollections; import org.odata4j.core.OComplexObject; import org.odata4j.core.OComplexObjects; import org.odata4j.core.ODataConstants; import org.odata4j.core.ODataVersion; import org.odata4j.core.OEntities; import org.odata4j.core.OEntity; import org.odata4j.core.OEntityKey; import org.odata4j.core.OLink; import org.odata4j.core.OObject; import org.odata4j.core.OProperties; import org.odata4j.core.OProperty; import org.odata4j.edm.EdmCollectionType; import org.odata4j.edm.EdmComplexType; import org.odata4j.edm.EdmDataServices; import org.odata4j.edm.EdmEntitySet; import org.odata4j.edm.EdmEntityType; import org.odata4j.edm.EdmProperty; import org.odata4j.edm.EdmProperty.CollectionKind; import org.odata4j.edm.EdmSimpleType; import org.odata4j.edm.EdmType; import org.odata4j.format.Entry; import org.odata4j.format.FormatParser; import org.odata4j.format.FormatWriter; import org.odata4j.format.Settings; import org.odata4j.producer.EntityResponse; import io.personium.common.es.util.PersoniumUUID; import io.personium.core.PersoniumCoreException; import io.personium.core.model.ctl.Common; import io.personium.core.model.ctl.Property; import io.personium.core.model.impl.es.odata.PropertyLimitChecker; import io.personium.core.model.impl.es.odata.PropertyLimitChecker.CheckError; import io.personium.core.odata.OEntityWrapper; import io.personium.core.odata.PersoniumFormatParserFactory; import io.personium.core.odata.PersoniumFormatWriterFactory; import io.personium.core.odata.PersoniumODataProducer; import io.personium.core.utils.EscapeControlCode; import io.personium.core.utils.ODataUtils; /** * OData??. */ public abstract class AbstractODataResource { /** * ??. */ private String entitySetName; /** * ??. */ public static final String DUMMY_KEY = "key_dummy@"; /** * ODataProducer. */ private PersoniumODataProducer odataProducer; /** $format?JSON. */ public static final String FORMAT_JSON = "json"; /** $format?atom. */ public static final String FORMAT_ATOM = "atom"; /** ??(?"SYSUTCDATETIME()"?????PersoniumJsonFromatParser?). */ private long currentTimeMillis = System.currentTimeMillis(); /** * entitySetName?. * @param entitySetName ?? */ public void setEntitySetName(String entitySetName) { this.entitySetName = entitySetName; } /** * odataProducer?. * @return odataProducer */ public PersoniumODataProducer getOdataProducer() { return this.odataProducer; } /** * odataProducer?. * @param odataProducer odataProducer */ public void setOdataProducer(PersoniumODataProducer odataProducer) { this.odataProducer = odataProducer; } /** * entitySetName?. * @return ?? */ public String getEntitySetName() { return this.entitySetName; } /** * ????ContentType???. * @param accept Accept ? * @param format $format * @return ????Content-Type */ public final MediaType decideOutputFormat(final String accept, final String format) { MediaType mediaType = null; if (format != null) { mediaType = decideOutputFormatFromQueryValue(format); } else if (accept != null) { mediaType = decideOutputFormatFromHeaderValues(accept); } if (mediaType == null) { // set default. mediaType = MediaType.APPLICATION_ATOM_XML_TYPE; } return mediaType; } /** * ??($format)??. * @param format $format? * @return ("application/json" or "application/atom+xml") */ private MediaType decideOutputFormatFromQueryValue(String format) { MediaType mediaType = null; if (format.equals(FORMAT_ATOM)) { // $format??atom??? mediaType = MediaType.APPLICATION_ATOM_XML_TYPE; } else if (format.equals(FORMAT_JSON)) { mediaType = MediaType.APPLICATION_JSON_TYPE; } else { throw PersoniumCoreException.OData.FORMAT_INVALID_ERROR.params(format); } return mediaType; } /** * Accept???. * @param format Accept? * @return ("application/json" or "application/atom+xml") */ private MediaType decideOutputFormatFromHeaderValues(String acceptHeaderValue) { MediaType mediaType = null; StringTokenizer st = new StringTokenizer(acceptHeaderValue, ","); while (st.hasMoreTokens()) { String accept = truncateAfterSemicolon(st.nextToken()); if (isAcceptXml(accept)) { mediaType = MediaType.APPLICATION_ATOM_XML_TYPE; } else if (isAcceptJson(accept)) { if (mediaType == null) { mediaType = MediaType.APPLICATION_JSON_TYPE; } } else { throw PersoniumCoreException.OData.UNSUPPORTED_MEDIA_TYPE.params(acceptHeaderValue); } } return mediaType; } /** * ????. * @param source Accept???? * @return ??? */ private String truncateAfterSemicolon(String source) { String result = source; int index = source.indexOf(";"); if (index >= 0) { result = source.substring(0, index); } return result; } private boolean isAcceptXml(String accept) { return accept.equals(MediaType.APPLICATION_ATOM_XML) || accept.equals(MediaType.APPLICATION_XML) || accept.equals(MediaType.WILDCARD); } private boolean isAcceptJson(String accept) { return accept.equals(MediaType.APPLICATION_JSON); } /** * Entity?? Producer??. * @param reader * @param odataResource OData * @return EntityResponse */ protected EntityResponse createEntity(final Reader reader, ODataCtlResource odataResource) { OEntityWrapper oew = getOEntityWrapper(reader, odataResource, null); // Entity?? Producer??.???????????? EntityResponse res = getOdataProducer().createEntity(getEntitySetName(), oew); return res; } /** * ?OEntityWrapper??. * @param reader * @param odataResource OData * @param metadata * @return OEntityWrapper */ public OEntityWrapper getOEntityWrapper(final Reader reader, ODataCtlResource odataResource, EdmDataServices metadata) { // ????OEntity? OEntity newEnt; if (metadata == null) { newEnt = createRequestEntity(reader, null); } else { newEnt = createRequestEntity(reader, null, metadata); } // ???. POST?If-Match ETag??????????etag?null String uuid = PersoniumUUID.randomUUID(); OEntityWrapper oew = new OEntityWrapper(uuid, newEnt, null); // ?????? odataResource.beforeCreate(oew); return oew; } /** * ?OEntity??. * ???????????????????????? * @param reader * @param oEntityKey ?entityKey???null? * @return OData */ protected OEntity createRequestEntity(final Reader reader, OEntityKey oEntityKey) { // ?? EdmDataServices metadata = this.odataProducer.getMetadata(); return createRequestEntity(reader, oEntityKey, metadata); } /** * ?OEntity??. * ???????????????????????? * @param reader * @param oEntityKey ?entityKey???null? * @param metadata EdmDataServices * @return OData */ protected OEntity createRequestEntity(final Reader reader, OEntityKey oEntityKey, EdmDataServices metadata) { return createRequestEntity(reader, oEntityKey, metadata, this.entitySetName); } /** * ?OEntity??. * ???????????????????????? * @param reader * @param oEntityKey ?entityKey???null? * @param metadata EdmDataServices * @param entitySetNameParam EntitySet?? * @return OData */ protected OEntity createRequestEntity(final Reader reader, OEntityKey oEntityKey, EdmDataServices metadata, String entitySetNameParam) { // ?? EdmEntitySet edmEntitySet = metadata.findEdmEntitySet(entitySetNameParam); EdmEntityType edmEntityType = edmEntitySet.getType(); // ???? List<String> keysDefined = edmEntityType.getKeys(); // ??????Ontity?? // ??OEntity????????????? OEntity reqEntity = createOEntityFromRequest(keysDefined, metadata, reader, entitySetNameParam); List<OLink> links = reqEntity.getLinks(); // TODO Static???? List<OProperty<?>> props = new ArrayList<OProperty<?>>(); List<String> schemaProps = new ArrayList<String>(); // ?? if (oEntityKey != null) { validatePrimaryKey(oEntityKey, edmEntityType); } for (EdmProperty ep : edmEntityType.getProperties()) { String propName = ep.getName(); schemaProps.add(propName); OProperty<?> op = null; try { // OEntity?? op = reqEntity.getProperty(propName); // ?__published?__updated??????400?? if (op != null && (propName.equals(Common.P_PUBLISHED.getName()) || propName.equals(Common.P_UPDATED.getName()))) { throw PersoniumCoreException.OData.FIELED_INVALID_ERROR .params(propName + " is management information name. Cannot request."); } if (ep.getType().isSimple()) { // ?? op = getSimpleProperty(ep, propName, op); } else { // Complex?? op = getComplexProperty(ep, propName, op, metadata); } } catch (PersoniumCoreException e) { throw e; } catch (Exception e) { op = setDefaultValue(ep, propName, op, metadata); } // ?????????? if (op != null && op.getValue() != null) { validateProperty(ep, propName, op); } if (op != null) { props.add(op); } } // DynamicProperty?? int dynamicPropCount = 0; for (OProperty<?> property : reqEntity.getProperties()) { String req = property.getName(); if (req.equals("__metadata")) { // ?__metadata??????400?? throw PersoniumCoreException.OData.FIELED_INVALID_ERROR .params(req + " is management information name. Cannot request."); } // EntityType????dynamicProperty????????????? // ?????declaredProperty??????????? if (!schemaProps.contains(req)) { // dynamicProperty?? dynamicPropCount++; validateDynamicProperty(property); props.add(property); } else { // ?????null????null???ES????????? // ????????ES?????????????? // ?????null???2??????? if (property.getValue() == null && isRegisteredDynamicProperty(edmEntityType, req)) { validateDynamicProperty(property); props.add(property); } } } // ????? this.collectProperties(props); this.validate(props); // ??? if (dynamicPropCount > 0) { PropertyLimitChecker checker = new PropertyLimitChecker(metadata, entitySetNameParam, dynamicPropCount); List<CheckError> errors = checker.checkPropertyLimits(entitySetNameParam); if (errors.size() > 0) { throw PersoniumCoreException.OData.ENTITYTYPE_STRUCTUAL_LIMITATION_EXCEEDED; } } // entity ?Immutable ?????????Entity?? // ??OEntity?????????????????? OEntity newEnt = OEntities.createRequest(edmEntitySet, props, links); // key OEntityKey key = null; // ???????? if (keysDefined.size() == 1) { // single-unnamed value String keyPropName = keysDefined.get(0); OProperty<?> keyProp = newEnt.getProperty(keyPropName); Object value = keyProp.getValue(); if (value == null) { // ??null???400 throw PersoniumCoreException.OData.NULL_SINGLE_KEY; } key = OEntityKey.create(keyProp.getValue()); } else { // multiple-named value? Map<String, Object> keyMap = new HashMap<String, Object>(); for (String keyPropName : keysDefined) { OProperty<?> keyProp = newEnt.getProperty(keyPropName); Object value = keyProp.getValue(); if (value == null) { // ?????null?? // ?null???OEntityKey???????? value = DUMMY_KEY; props.remove(keyProp); props.add(OProperties.string(keyPropName, (String) null)); } keyMap.put(keyPropName, value); } key = OEntityKey.create(keyMap); } editProperty(props, key.toKeyString()); // ????OEntity? // ??OEntity?????????????????? newEnt = OEntities.create(reqEntity.getEntitySet(), key, props, links, key.toKeyStringWithoutParentheses(), reqEntity.getEntitySet().getName()); return newEnt; } /** * ????DynamicProperty???????. * @param edmEntityType edmEntityType * @param propertyName ?? * @return true:DynamicProperty, false:DeclaredProperty */ protected boolean isRegisteredDynamicProperty(EdmEntityType edmEntityType, String propertyName) { boolean isRegisteredDynamicProperty = false; EdmProperty prop = edmEntityType.findDeclaredProperty(propertyName); NamespacedAnnotation<?> isDeclared = prop.findAnnotation(Common.P_NAMESPACE.getUri(), Property.P_IS_DECLARED.getName()); // Property/ComplexTypeProperty???IsDeclared?????????? if (isDeclared != null && isDeclared.getValue().equals("false")) { isRegisteredDynamicProperty = true; } return isRegisteredDynamicProperty; } /** * ??. * @param oEntityKey ??Key * @param edmEntityType EntityType? */ protected void validatePrimaryKey(OEntityKey oEntityKey, EdmEntityType edmEntityType) { for (String key : edmEntityType.getKeys()) { EdmType keyEdmType = edmEntityType.findProperty(key).getType(); if (OEntityKey.KeyType.SINGLE.equals(oEntityKey.getKeyType())) { // ??? if (!(oEntityKey.asSingleValue().getClass().equals( EdmSimpleType.getSimple(keyEdmType.getFullyQualifiedTypeName()).getCanonicalJavaType()))) { throw PersoniumCoreException.OData.ENTITY_KEY_PARSE_ERROR; } } else { // ??? Set<NamedValue<?>> nvSet = oEntityKey.asComplexValue(); for (NamedValue<?> nv : nvSet) { if (nv.getName().equals(key) && !(nv.getValue().getClass().equals(EdmSimpleType .getSimple(keyEdmType.getFullyQualifiedTypeName()).getCanonicalJavaType()))) { throw PersoniumCoreException.OData.ENTITY_KEY_PARSE_ERROR; } } } } } /** * ?. * @param props * @param value ? */ protected void editProperty(List<OProperty<?>> props, String value) { } /** * ????. * @param ep EdmProperty * @param propName ?? * @param op OProperty * @return ?? */ protected OProperty<?> getSimpleProperty(EdmProperty ep, String propName, OProperty<?> op) { // ????????? if (op == null || op.getValue() == null) { op = setDefaultValue(ep, propName, op); } return op; } /** * ??Complex??. * @param ep EdmProperty * @param propName ?? * @param op OProperty * @param metadata * @return ??Complex */ @SuppressWarnings("unchecked") protected OProperty<?> getComplexProperty(EdmProperty ep, String propName, OProperty<?> op, EdmDataServices metadata) { // ComplexType??? OProperty<?> newProp; EdmComplexType edmComplexType = metadata.findEdmComplexType(ep.getType().getFullyQualifiedTypeName()); // dynamicProperty?? if (op == null || op.getValue() == null) { newProp = setDefaultValue(ep, propName, op, metadata); } else { if (ep.getCollectionKind().equals(CollectionKind.List)) { // ComplexType???????OCollectionBuilder?? EdmCollectionType collectionType = new EdmCollectionType(CollectionKind.List, ep.getType()); OCollection.Builder<OObject> builder = OCollections .<OObject>newBuilder(collectionType.getItemType()); if (op.getValue() instanceof OCollection<?>) { // ComplexType??? for (OComplexObject val : (OCollection<OComplexObject>) op.getValue()) { // ComplexType?OProperty?? List<OProperty<?>> newComplexProperties = getComplexPropertyList(ep, propName, val.getProperties(), metadata); builder.add(OComplexObjects.create(edmComplexType, newComplexProperties)); } // ComplexType???OCollection???? newProp = OProperties.collection(ep.getName(), collectionType, builder.build()); } else { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } } else { // ComplexType????????ComplexType???? List<OProperty<?>> newComplexProperties = getComplexPropertyList(ep, propName, (List<OProperty<?>>) op.getValue(), metadata); newProp = OProperties.complex(propName, edmComplexType, newComplexProperties); } } return newProp; } /** * ??Complex??. * @param ep EdmProperty * @param propName ?? * @param opList OProperty * @param metadata * @return ?? */ protected List<OProperty<?>> getComplexPropertyList(EdmProperty ep, String propName, List<OProperty<?>> opList, EdmDataServices metadata) { // ComplexType??? EdmComplexType edmComplexType = metadata.findEdmComplexType(ep.getType().getFullyQualifiedTypeName()); Map<String, OProperty<?>> complexProperties = new HashMap<String, OProperty<?>>(); // ????????????OProperty?Hash???? for (OProperty<?> cp : opList) { complexProperties.put(cp.getName(), cp); } List<OProperty<?>> newComplexProperties = createNewComplexProperties(metadata, edmComplexType, complexProperties); // ??ComplexType??? return newComplexProperties; } /** * ComplexType????????. * @param metadata * @param edmComplexType ComplexType? * @param complexProperties ComplexTypeProperty?List * @return ??ComplexType? */ protected List<OProperty<?>> createNewComplexProperties(EdmDataServices metadata, EdmComplexType edmComplexType, Map<String, OProperty<?>> complexProperties) { List<OProperty<?>> newComplexProperties = new ArrayList<OProperty<?>>(); for (EdmProperty ctp : edmComplexType.getProperties()) { // ?? String compPropName = ctp.getName(); OProperty<?> complexProperty = complexProperties.get(compPropName); if (ctp.getType().isSimple()) { // ?? complexProperty = getSimpleProperty(ctp, compPropName, complexProperty); } else { // Complex?? complexProperty = getComplexProperty(ctp, compPropName, complexProperty, metadata); } if (complexProperty != null) { newComplexProperties.add(complexProperty); } } return newComplexProperties; } /** * ?. * @param ep EdmProperty * @param propName ?? * @param op OProperty * @return Oproperty */ protected OProperty<?> setDefaultValue(EdmProperty ep, String propName, OProperty<?> op) { return setDefaultValue(ep, propName, op, null); } /** * ?. * @param ep EdmProperty * @param propName ?? * @param op OProperty * @param metadata EdmDataServices * @return Oproperty */ protected OProperty<?> setDefaultValue(EdmProperty ep, String propName, OProperty<?> op, EdmDataServices metadata) { // ????????? Property // ???????? // ComplexType?????????????????? NamespacedAnnotation<?> annotation = ep.findAnnotation(Common.P_NAMESPACE.getUri(), Property.P_IS_DECLARED.getName()); if (annotation != null && !(Boolean.valueOf(annotation.getValue().toString()))) { return null; } if (ep.getType().isSimple() && !ep.getCollectionKind().equals(CollectionKind.List) && ep.getDefaultValue() != null) { op = generateDefautlProperty(ep); } else if (ep.isNullable()) { // nullable?true???null??? // TODO ?????? op = OProperties.null_(propName, ep.getType().getFullyQualifiedTypeName()); } else { // nullable?false????? throw PersoniumCoreException.OData.INPUT_REQUIRED_FIELD_MISSING.params(propName); } return op; } /** * ???. * @param ep EdmProperty * @param propName ?? * @param op OProperty */ protected void validateProperty(EdmProperty ep, String propName, OProperty<?> op) { for (NamespacedAnnotation<?> annotation : ep.getAnnotations()) { if (annotation.getName().equals(Common.P_FORMAT)) { String pFormat = annotation.getValue().toString(); // ????? if (pFormat.startsWith(Common.P_FORMAT_PATTERN_REGEX)) { validatePropertyRegEx(propName, op, pFormat); } else if (pFormat.equals(Common.P_FORMAT_PATTERN_URI)) { validatePropertyUri(propName, op); } else if (pFormat.startsWith(Common.P_FORMAT_PATTERN_SCHEMA_URI)) { validatePropertySchemaUri(propName, op); } else if (pFormat.startsWith(Common.P_FORMAT_PATTERN_CELL_URL)) { validatePropertyCellUrl(propName, op); } else if (pFormat.startsWith(Common.P_FORMAT_PATTERN_USUSST)) { validatePropertyUsusst(propName, op, pFormat); } else if (pFormat.startsWith(Common.P_FORMAT_PATTERN_MESSAGE_REQUEST_RELATION)) { validatePropertyMessageRequestRelation(propName, op); } } } } /** * p:Format???. * @param props * @param */ public void validate(List<OProperty<?>> props) { } /** * ??. * @param props * @param */ public void collectProperties(List<OProperty<?>> props) { } /** * ???. * @param property OProperty */ private void validateDynamicProperty(OProperty<?> property) { // key?? String key = property.getName(); Pattern pattern = Pattern.compile(Common.PATTERN_USERDATA_KEY); Matcher matcher = pattern.matcher(key); if (!matcher.matches()) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(key); } // ???null?? if (property.getValue() == null) { return; } // String?value?? EdmType type = property.getType(); if (EdmSimpleType.STRING.equals(type)) { String value = property.getValue().toString(); if (!ODataUtils.validateString(value)) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(key); } } // Double?? if (EdmSimpleType.DOUBLE.equals(type)) { double value = (Double) property.getValue(); if (!ODataUtils.validateDouble(value)) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(key); } } } /** * ??????. * @param propName ?? * @param op OProperty * @param pFormat pFormat? */ protected void validatePropertyRegEx(String propName, OProperty<?> op, String pFormat) { // Extract regular expressions from('regular expression') Pattern formatPattern = Pattern.compile(Common.P_FORMAT_PATTERN_REGEX + "\\('(.+)'\\)"); Matcher formatMatcher = formatPattern.matcher(pFormat); formatMatcher.matches(); pFormat = formatMatcher.group(1); if (!ODataUtils.validateRegEx(op.getValue().toString(), pFormat)) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } } /** * ?URI???. * @param propName ?? * @param op OProperty */ protected void validatePropertyUri(String propName, OProperty<?> op) { if (!ODataUtils.isValidUri(op.getValue().toString())) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } } /** * Schema URI Format Check. * @param propName Property name * @param op OProperty */ protected void validatePropertySchemaUri(String propName, OProperty<?> op) { if (!ODataUtils.isValidSchemaUri(op.getValue().toString())) { throw PersoniumCoreException.OData.SCHEMA_URI_FORMAT_ERROR.params(propName); } } /** * Cell URL Format Check. * @param propName Property name * @param op OProperty */ protected void validatePropertyCellUrl(String propName, OProperty<?> op) { if (!ODataUtils.isValidCellUrl(op.getValue().toString())) { throw PersoniumCoreException.OData.CELL_URL_FORMAT_ERROR.params(propName); } } /** * ??1????????. * @param propName ?? * @param op OProperty * @param pFormat pFormat? */ protected void validatePropertyUsusst(String propName, OProperty<?> op, String pFormat) { // pFormat????. Pattern formatPattern = Pattern.compile(Common.P_FORMAT_PATTERN_USUSST + "\\((.+)\\)"); Matcher formatMatcher = formatPattern.matcher(pFormat); formatMatcher.matches(); pFormat = formatMatcher.group(1); String[] allowedTokens = pFormat.split(", "); for (int i = 0; i < allowedTokens.length; i++) { //remove single quotations. allowedTokens[i] = allowedTokens[i].replaceAll("\'(.+)\'", "$1"); } List<String> allowedTokenList = Arrays.asList(allowedTokens); // ???? String value = op.getValue().toString(); if (value.indexOf(" ") > -1) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } String[] tokens = value.split(" "); Set<String> overlapChk = new HashSet<>(); // ????????? // 1???????????? for (String token : tokens) { if (!allowedTokenList.contains(token)) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } //?? if (overlapChk.contains(token)) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } else { overlapChk.add(token); } } } /** * Message RequestRelation Format Check. * @param propName Property name * @param op OProperty */ protected void validatePropertyMessageRequestRelation(String propName, OProperty<?> op) { if (!ODataUtils.validateClassUrl(op.getValue().toString(), Common.PATTERN_RELATION_CLASS_URL) && !ODataUtils.validateRegEx(op.getValue().toString(), Common.PATTERN_RELATION_NAME) && !ODataUtils.validateClassUrl(op.getValue().toString(), Common.PATTERN_ROLE_CLASS_URL) && !ODataUtils.validateRegEx(op.getValue().toString(), Common.PATTERN_NAME)) { throw PersoniumCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propName); } } /** * OEntityKey???. * ??OEntityKeytoKeyString?????????? * @param oEntityKey ??OEntityKey * @param edmEntitySet EdmEntitySet * @return OEntityKey ???OEntityKey */ public static OEntityKey normalizeOEntityKey(OEntityKey oEntityKey, EdmEntitySet edmEntitySet) { EdmEntityType edmEntityType = edmEntitySet.getType(); // ???? List<String> keysDefined = edmEntityType.getKeys(); // key OEntityKey key = null; // ???????? if (keysDefined.size() == 1) { key = oEntityKey; } else { Map<String, Object> keyMap = new HashMap<String, Object>(); if (OEntityKey.KeyType.COMPLEX == oEntityKey.getKeyType()) { // ????? Set<NamedValue<?>> nvSet = oEntityKey.asComplexValue(); // multiple-named value? for (String keyName : keysDefined) { for (NamedValue<?> nv : nvSet) { if (nv.getName().equals(keyName)) { // Map??? Object value = nv.getValue(); if (value == null) { // ?????null?? // ?null???OEntityKey???????? value = DUMMY_KEY; } keyMap.put(keyName, value); } } } } else { // ????? Object keyValue = oEntityKey.asSingleValue(); for (String keyName : keysDefined) { EdmProperty eProp = edmEntityType.findProperty(keyName); Object value = null; if (eProp.isNullable()) { // Nullable??null????? // ?null???OEntityKey???????? value = DUMMY_KEY; } else { value = keyValue; } keyMap.put(keyName, value); } } // ??Map?OEntityKey? key = OEntityKey.create(keyMap); } return key; } /** * Reader?OEntity??. * @param keyPropNames ?????????? * @param reader * @return OEntity */ private OEntity createOEntityFromRequest(List<String> keyPropNames, EdmDataServices metadata, Reader reader, String entitySetNameParam) { OEntityKey keyDummy = null; if (keyPropNames.size() == 1) { // single-unnamed value keyDummy = OEntityKey.create(""); } // TODO multiple-named value? OEntity entity = null; // ODataVersion.V2????????????JSON????????V1???? entity = convertFromString(reader, MediaType.APPLICATION_JSON_TYPE, ODataVersion.V1, metadata, entitySetNameParam, keyDummy); return entity; } /** * POST????. * @param ent OEntity * @param outputFormat Content-Type * @param responseStr ? * @param resUriInfo ??UriInfo * @param key ?? * @return ? */ protected ResponseBuilder getPostResponseBuilder(OEntity ent, MediaType outputFormat, String responseStr, UriInfo resUriInfo, String key) { ResponseBuilder rb = Response.status(HttpStatus.SC_CREATED).entity(responseStr).type(outputFormat) .header(HttpHeaders.LOCATION, resUriInfo.getBaseUri().toASCIIString() + getEntitySetName() + key) .header(ODataConstants.Headers.DATA_SERVICE_VERSION, ODataVersion.V2.asString); // ?ETAG if (ent instanceof OEntityWrapper) { OEntityWrapper oew2 = (OEntityWrapper) ent; String etag = oew2.getEtag(); if (etag != null) { rb = rb.header(HttpHeaders.ETAG, "W/\"" + etag + "\""); } } return rb; } /** * ???. * @param uriInfo UriInfo * @param resp ? * @param format ?? * @param acceptableMediaTypes ??MediaType? * @return ? */ protected String renderEntityResponse(final UriInfo uriInfo, final EntityResponse resp, final String format, final List<MediaType> acceptableMediaTypes) { StringWriter w = new StringWriter(); try { FormatWriter<EntityResponse> fw = PersoniumFormatWriterFactory.getFormatWriter(EntityResponse.class, acceptableMediaTypes, format, null); // UriInfo uriInfo2 = PersoniumCoreUtils.createUriInfo(uriInfo, 1); fw.write(uriInfo, w, resp); } catch (UnsupportedOperationException e) { throw PersoniumCoreException.OData.FORMAT_INVALID_ERROR.params(format); } String responseStr = w.toString(); return responseStr; } /** * Entity Data Model??OData???. * @param ep Entity Data Model? * @return ???OData? */ private OProperty<?> generateDefautlProperty(EdmProperty ep) { EdmType edmType = ep.getType(); OProperty<?> op = null; // ?Default?? String defaultValue = ep.getDefaultValue(); String propName = ep.getName(); // Default????????? if (EdmSimpleType.STRING.equals(edmType)) { // Type??Default?CELLID()???? if (defaultValue.equals("UUID()")) { // Type??Default?UUID()???? String newUuid = UUID.randomUUID().toString().replaceAll("-", ""); op = OProperties.string(propName, newUuid); } else if (defaultValue.equals("null")) { // Type??Default?null???? op = OProperties.null_(propName, EdmSimpleType.STRING); } else { // Type??Default???????? op = OProperties.string(propName, defaultValue); } } else if (EdmSimpleType.DATETIME.equals(edmType)) { // Edm.DateTime if (null == defaultValue || defaultValue.equals("null")) { // defaultValue?null???"null"????null? op = OProperties.null_(propName, EdmSimpleType.DATETIME); } else { // ?"\/Date(...)\/"????? // ?"SYSUTCDATETIME()"?????? // TODO ???? Atom ?Default TimeZone?????? op = OProperties.datetime(propName, new Date(getTimeMillis(defaultValue))); } } else if (EdmSimpleType.SINGLE.equals(edmType)) { // Type?SINGLE?Default????? op = OProperties.single(propName, Float.valueOf(defaultValue)); } else if (EdmSimpleType.INT64.equals(edmType)) { // Type?INT64?Default????? op = OProperties.int64(propName, Long.valueOf(defaultValue)); } else if (EdmSimpleType.INT32.equals(edmType)) { // Type?INT32?Default????? op = OProperties.int32(propName, Integer.valueOf(defaultValue)); } else if (EdmSimpleType.BOOLEAN.equals(edmType)) { // Type?Boolean?Default????? op = OProperties.boolean_(propName, Boolean.parseBoolean(defaultValue)); } else if (EdmSimpleType.DOUBLE.equals(edmType)) { // Type?Double?Default????? op = OProperties.double_(propName, Double.parseDouble(defaultValue)); } return op; } private static OEntity convertFromString(final Reader body, final MediaType type, final ODataVersion version, final EdmDataServices metadata, final String entitySetName, final OEntityKey entityKey) { FormatParser<Entry> parser = PersoniumFormatParserFactory.getParser(Entry.class, type, new Settings(version, metadata, entitySetName, entityKey, null, false)); Entry entry = null; try { entry = parser.parse(body); } catch (PersoniumCoreException e) { throw e; } catch (Exception e) { throw PersoniumCoreException.OData.JSON_PARSE_ERROR.reason(e); } return entry.getEntity(); } /** * ?. * @param value ?? * @return true: false: */ public static boolean isDummy(Object value) { boolean flag = false; if (value.equals(DUMMY_KEY)) { flag = true; } return flag; } /** * null????????. * @param value ? * @return */ public static String replaceDummyKeyToNull(String value) { return value.replaceAll("'" + DUMMY_KEY + "'", "null"); } /** * null????????(???). * @param value ? * @return */ public static String replaceNullToDummyKeyWithParenthesis(String value) { return replaceNullToDummyKey("(" + value + ")"); } /** * null????????. * @param value ? * @return */ public static String replaceNullToDummyKey(String value) { Pattern pattern = Pattern.compile("=null([,|\\)])"); Matcher m = pattern.matcher(value); return m.replaceAll("='" + DUMMY_KEY + "'$1"); } /** * NavigationTargetKeyProperty?EntityType?PropertyName??. * @param propertyName ?? * @return EntityType?PropertyName */ public static HashMap<String, String> convertNTKP(String propertyName) { HashMap<String, String> ntkp = null; Pattern pattern = Pattern.compile("_([^.]+)\\.(.+)"); Matcher m = pattern.matcher(propertyName); if (m.matches()) { ntkp = new HashMap<String, String>(); ntkp.put("entityType", m.group(1)); ntkp.put("propName", m.group(2)); } return ntkp; } /** * ???TimeMillis??????. * @param timeStr TimeMillis??(ex."/Data(...)/", "SYSUTCDATETIME()") * @return TimeMillis? */ private long getTimeMillis(String timeStr) { long timeMillis = 0; if (timeStr.equals(Common.SYSUTCDATETIME)) { timeMillis = currentTimeMillis; } else { try { Pattern pattern = Pattern.compile("^/Date\\((.+)\\)/$"); Matcher match = pattern.matcher(timeStr); if (match.matches()) { String date = match.replaceAll("$1"); timeMillis = Long.parseLong(date); } } catch (NumberFormatException e) { throw PersoniumCoreException.OData.JSON_PARSE_ERROR.reason(e); } } return timeMillis; } /** * ???. * @param response ? * @return ??? */ public String escapeResponsebody(String response) { return EscapeControlCode.escape(response); } }