| /** |
| *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. |
| */ |
| /* |
| * endpoint_descriptor_reader.c |
| * |
| * \date 24 Jul 2014 |
| * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a> |
| * \copyright Apache License, Version 2.0 |
| */ |
| |
| #include <stdbool.h> |
| #include <string.h> |
| #include <libxml/xmlreader.h> |
| |
| #include "log_helper.h" |
| #include "remote_constants.h" |
| |
| #include "endpoint_description.h" |
| #include "endpoint_descriptor_common.h" |
| #include "endpoint_descriptor_reader.h" |
| |
| struct endpoint_descriptor_reader { |
| xmlTextReaderPtr reader; |
| log_helper_pt* loghelper; |
| }; |
| |
| static valueType valueTypeFromString(char *name); |
| |
| celix_status_t endpointDescriptorReader_create(endpoint_discovery_poller_pt poller, endpoint_descriptor_reader_pt *reader) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| *reader = malloc(sizeof(**reader)); |
| if (!*reader) { |
| status = CELIX_ENOMEM; |
| } else { |
| (*reader)->reader = NULL; |
| (*reader)->loghelper = poller->loghelper; |
| } |
| |
| return status; |
| } |
| |
| celix_status_t endpointDescriptorReader_destroy(endpoint_descriptor_reader_pt reader) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| reader->loghelper = NULL; |
| |
| free(reader); |
| |
| return status; |
| } |
| |
| void endpointDescriptorReader_addSingleValuedProperty(properties_pt properties, const xmlChar* name, const xmlChar* value) { |
| properties_set(properties, (char *) name, (char*) value); |
| } |
| |
| void endpointDescriptorReader_addMultiValuedProperty(properties_pt properties, const xmlChar* name, array_list_pt values) { |
| char *value = calloc(256, sizeof(*value)); |
| if (value) { |
| unsigned int size = arrayList_size(values); |
| unsigned int i; |
| for (i = 0; i < size; i++) { |
| char* item = (char*) arrayList_get(values, i); |
| if (i > 0) { |
| value = strcat(value, ","); |
| } |
| value = strcat(value, item); |
| } |
| |
| properties_set(properties, (char *) name, value); |
| |
| free(value); |
| } |
| } |
| |
| celix_status_t endpointDescriptorReader_parseDocument(endpoint_descriptor_reader_pt reader, char *document, array_list_pt *endpoints) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| reader->reader = xmlReaderForMemory(document, (int) strlen(document), NULL, "UTF-8", 0); |
| if (reader->reader == NULL) { |
| status = CELIX_BUNDLE_EXCEPTION; |
| } else { |
| bool inProperty = false; |
| bool inXml = false; |
| bool inArray = false; |
| bool inList = false; |
| bool inSet = false; |
| bool inValue = false; |
| |
| const xmlChar *propertyName = NULL; |
| const xmlChar *propertyValue = NULL; |
| valueType propertyType = VALUE_TYPE_STRING; |
| xmlChar *valueBuffer = xmlMalloc(256); |
| valueBuffer[0] = '\0'; |
| |
| array_list_pt propertyValues = NULL; |
| arrayList_create(&propertyValues); |
| |
| array_list_pt endpointDescriptions = NULL; |
| if (*endpoints) { |
| // use the given arraylist... |
| endpointDescriptions = *endpoints; |
| } else { |
| arrayList_create(&endpointDescriptions); |
| // return the read endpoints... |
| *endpoints = endpointDescriptions; |
| } |
| |
| properties_pt endpointProperties = NULL; |
| |
| int read = xmlTextReaderRead(reader->reader); |
| while (read == XML_TEXTREADER_MODE_INTERACTIVE) { |
| int type = xmlTextReaderNodeType(reader->reader); |
| |
| if (type == XML_READER_TYPE_ELEMENT) { |
| const xmlChar *localname = xmlTextReaderConstLocalName(reader->reader); |
| |
| if (inXml) { |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "<"); |
| valueBuffer = xmlStrcat(valueBuffer, localname); |
| |
| int i = xmlTextReaderMoveToFirstAttribute(reader->reader); |
| while (i == 1) { |
| const xmlChar *name = xmlTextReaderConstName(reader->reader); |
| const xmlChar *value = xmlTextReaderConstValue(reader->reader); |
| |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST " "); |
| valueBuffer = xmlStrcat(valueBuffer, name); |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "=\""); |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST value); |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "\""); |
| |
| i = xmlTextReaderMoveToNextAttribute(reader->reader); |
| } |
| |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST ">"); |
| } else if (xmlStrcmp(localname, ENDPOINT_DESCRIPTION) == 0) { |
| |
| if (endpointProperties != NULL) |
| properties_destroy(endpointProperties); |
| |
| endpointProperties = properties_create(); |
| } else if (xmlStrcmp(localname, PROPERTY) == 0) { |
| inProperty = true; |
| |
| propertyName = xmlTextReaderGetAttribute(reader->reader, NAME); |
| propertyValue = xmlTextReaderGetAttribute(reader->reader, VALUE); |
| xmlChar *vtype = xmlTextReaderGetAttribute(reader->reader, VALUE_TYPE); |
| propertyType = valueTypeFromString((char*) vtype); |
| arrayList_clear(propertyValues); |
| |
| if (xmlTextReaderIsEmptyElement(reader->reader)) { |
| inProperty = false; |
| |
| if (propertyValue != NULL) { |
| if (propertyType != VALUE_TYPE_STRING && strcmp(OSGI_RSA_ENDPOINT_SERVICE_ID, (char*) propertyName)) { |
| logHelper_log(*reader->loghelper, OSGI_LOGSERVICE_WARNING, "ENDPOINT_DESCRIPTOR_READER: Only single-valued string supported for %s\n", propertyName); |
| } |
| |
| endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, propertyValue); |
| } |
| |
| xmlFree((void *) propertyName); |
| xmlFree((void *) propertyValue); |
| xmlFree((void *) vtype); |
| } |
| } else { |
| valueBuffer[0] = 0; |
| inArray |= inProperty && xmlStrcmp(localname, ARRAY) == 0; |
| inList |= inProperty && xmlStrcmp(localname, LIST) == 0; |
| inSet |= inProperty && xmlStrcmp(localname, SET) == 0; |
| inXml |= inProperty && xmlStrcmp(localname, XML) == 0; |
| inValue |= inProperty && xmlStrcmp(localname, VALUE) == 0; |
| } |
| } else if (type == XML_READER_TYPE_END_ELEMENT) { |
| const xmlChar *localname = xmlTextReaderConstLocalName(reader->reader); |
| |
| if (inXml) { |
| if (xmlStrcmp(localname, XML) != 0) { |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "</"); |
| valueBuffer = xmlStrcat(valueBuffer, localname); |
| valueBuffer = xmlStrcat(valueBuffer, BAD_CAST ">"); |
| } |
| else { |
| inXml = false; |
| } |
| } else if (xmlStrcmp(localname, ENDPOINT_DESCRIPTION) == 0) { |
| endpoint_description_pt endpointDescription = NULL; |
| // Completely parsed endpoint description, add it to our list of results... |
| endpointDescription_create(endpointProperties, &endpointDescription); |
| arrayList_add(endpointDescriptions, endpointDescription); |
| |
| endpointProperties = properties_create(); |
| } else if (xmlStrcmp(localname, PROPERTY) == 0) { |
| inProperty = false; |
| |
| if (inArray || inList || inSet) { |
| endpointDescriptorReader_addMultiValuedProperty(endpointProperties, propertyName, propertyValues); |
| } |
| else if (propertyValue != NULL) { |
| if (propertyType != VALUE_TYPE_STRING) { |
| logHelper_log(*reader->loghelper, OSGI_LOGSERVICE_WARNING, "ENDPOINT_DESCRIPTOR_READER: Only string support for %s\n", propertyName); |
| } |
| endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, propertyValue); |
| |
| xmlFree((void *) propertyValue); |
| } |
| else { |
| endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, valueBuffer); |
| } |
| |
| xmlFree((void *) propertyName); |
| unsigned int k=0; |
| for(;k<arrayList_size(propertyValues);k++){ |
| free(arrayList_get(propertyValues,k)); |
| } |
| arrayList_clear(propertyValues); |
| |
| propertyType = VALUE_TYPE_STRING; |
| inArray = false; |
| inList = false; |
| inSet = false; |
| inXml = false; |
| } else if (xmlStrcmp(localname, VALUE) == 0) { |
| arrayList_add(propertyValues, strdup((char*) valueBuffer)); |
| valueBuffer[0] = 0; |
| inValue = false; |
| } |
| } else if (type == XML_READER_TYPE_TEXT) { |
| if (inValue || inXml) { |
| const xmlChar *value = xmlTextReaderValue(reader->reader); |
| valueBuffer = xmlStrcat(valueBuffer, value); |
| xmlFree((void *)value); |
| } |
| } |
| |
| read = xmlTextReaderRead(reader->reader); |
| } |
| |
| if(endpointProperties!=NULL){ |
| properties_destroy(endpointProperties); |
| } |
| |
| unsigned int k=0; |
| for(;k<arrayList_size(propertyValues);k++){ |
| free(arrayList_get(propertyValues,k)); |
| } |
| arrayList_destroy(propertyValues); |
| xmlFree(valueBuffer); |
| |
| xmlFreeTextReader(reader->reader); |
| } |
| |
| return status; |
| } |
| |
| static valueType valueTypeFromString(char *name) { |
| if (name == NULL || strcmp(name, "") == 0 || strcmp(name, "String") == 0) { |
| return VALUE_TYPE_STRING; |
| } else if (strcmp(name, "long") == 0 || strcmp(name, "Long") == 0) { |
| return VALUE_TYPE_LONG; |
| } else if (strcmp(name, "double") == 0 || strcmp(name, "Double") == 0) { |
| return VALUE_TYPE_DOUBLE; |
| } else if (strcmp(name, "float") == 0 || strcmp(name, "Float") == 0) { |
| return VALUE_TYPE_FLOAT; |
| } else if (strcmp(name, "int") == 0 || strcmp(name, "integer") == 0 || strcmp(name, "Integer") == 0) { |
| return VALUE_TYPE_INTEGER; |
| } else if (strcmp(name, "short") == 0 || strcmp(name, "Short") == 0) { |
| return VALUE_TYPE_SHORT; |
| } else if (strcmp(name, "byte") == 0 || strcmp(name, "Byte") == 0) { |
| return VALUE_TYPE_BYTE; |
| } else if (strcmp(name, "char") == 0 || strcmp(name, "Character") == 0) { |
| return VALUE_TYPE_CHAR; |
| } else if (strcmp(name, "boolean") == 0 || strcmp(name, "Boolean") == 0) { |
| return VALUE_TYPE_BOOLEAN; |
| } else { |
| return VALUE_TYPE_STRING; |
| } |
| } |
| |
| #ifdef RSA_ENDPOINT_TEST_READER |
| int main() { |
| array_list_pt list = NULL; |
| endpoint_descriptor_reader_pt reader = NULL; |
| |
| char *doc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" |
| "<endpoint-descriptions xmlns=\"http://www.osgi.org/xmlns/rsa/v1.0.0\">" |
| "<endpoint-description>" |
| "<property name=\"endpoint.service.id\" value-type=\"long\" value=\"6\"/>" |
| "<property name=\"endpoint.framework.uuid\" value=\"2983D849-93B1-4C2C-AC6D-5BCDA93ACB96\"/>" |
| "<property name=\"service.intents\">" |
| "<list>" |
| "<value>SOAP</value>" |
| "<value>HTTP</value>" |
| "</list>" |
| "</property>" |
| "<property name=\"endpoint.id\" value=\"11111111-1111-1111-1111-111111111111\" />" |
| "<property name=\"objectClass\"><array><value>com.acme.Foo</value></array></property>" |
| "<property name=\"endpoint.package.version.com.acme\" value=\"4.2\" />" |
| "<property name=\"service.imported.configs\" value=\"com.acme\" />" |
| "<property name=\"service.imported\" value=\"true\"/>" |
| "<property name=\"com.acme.ws.xml\">" |
| "<xml>" |
| "<config xmlns=\"http://acme.com/defs\">" |
| "<port>1029</port>" |
| "<host>www.acme.com</host>" |
| "</config>" |
| "</xml>" |
| "</property>" |
| "</endpoint-description>" |
| "<endpoint-description>" |
| "<property name=\"endpoint.service.id\" value-type=\"long\" value=\"5\"/>" |
| "<property name=\"endpoint.framework.uuid\" value=\"2983D849-93B1-4C2C-AC6D-5BCDA93ACB96\"/>" |
| "<property name=\"service.intents\">" |
| "<list>" |
| "<value>SOAP</value>" |
| "<value>HTTP</value>" |
| "</list>" |
| "</property>" |
| "<property name=\"endpoint.id\" value=\"22222222-2222-2222-2222-222222222222\" />" |
| "<property name=\"objectClass\"><array><value>com.acme.Bar</value></array></property>" |
| "<property name=\"endpoint.package.version.com.acme\" value=\"4.2\" />" |
| "<property name=\"service.imported.configs\" value=\"com.acme\" />" |
| "<property name=\"com.acme.ws.xml\">" |
| "<xml>" |
| "<config xmlns=\"http://acme.com/defs\">" |
| "<port>1029</port>" |
| "<host>www.acme.com</host>" |
| "</config>" |
| "</xml>" |
| "</property>" |
| "</endpoint-description>" |
| "</endpoint-descriptions>"; |
| |
| endpointDescriptorReader_create(&reader); |
| |
| endpointDescriptorReader_parseDocument(reader, doc, &list); |
| |
| int i; |
| for (i = 0; i < arrayList_size(list); i++) { |
| printf("\nEndpoint description #%d:\n", (i+1)); |
| endpoint_description_pt edp = arrayList_get(list, i); |
| printf("Id: %s\n", edp->id); |
| printf("Service Id: %ld\n", edp->serviceId); |
| printf("Framework UUID: %s\n", edp->frameworkUUID); |
| printf("Service: %s\n", edp->service); |
| |
| properties_pt props = edp->properties; |
| if (props) { |
| printf("Service properties:\n"); |
| hash_map_iterator_pt iter = hashMapIterator_create(props); |
| while (hashMapIterator_hasNext(iter)) { |
| hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); |
| |
| printf("- %s => '%s'\n", hashMapEntry_getKey(entry), hashMapEntry_getValue(entry)); |
| } |
| hashMapIterator_destroy(iter); |
| } else { |
| printf("No service properties...\n"); |
| } |
| |
| |
| endpointDescription_destroy(edp); |
| } |
| |
| if (list != NULL) { |
| arrayList_destroy(list); |
| } |
| |
| endpointDescriptorReader_destroy(reader); |
| |
| return 0; |
| } |
| #endif |