How to check if public X509Certificate is trusted - x509certificate

I've signed XML which I validate by code below
<ThreeDSecure>
<Message id="pareq_1514467844949">
<PARes id="WkTyB5IWvmwx1d846aVCTg">
<version>1.0.2</version>
<Merchant>
<acqBIN>454589</acqBIN>
<merID>P2P_WEB</merID>
</Merchant>
<Purchase>
<xid>MTUxNDQ2Nzg0NDk0OTAwMDAwMDA=</xid>
<date>20171228 16:30:44</date>
<purchAmount>1000</purchAmount>
<currency>810</currency>
<exponent>2</exponent>
</Purchase>
<pan>0000000000002635</pan>
<TX>
<time>20171228 13:31:04</time>
<status>Y</status>
<cavv>AAABB3YieEkDliVhUyJ4AAAAAAA=</cavv>
<eci>05</eci>
<cavvAlgorithm>2</cavvAlgorithm>
</TX>
</PARes>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#WkTyB5IWvmwx1d846aVCTg">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>vjiyJgkYUPKeX79NBcvZNcZuH7g=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>LcITisdhnjQSLaQnL/VPg8EWCFbmfDhDpOLo8xGntbcCiubVCi6o+luhu38JA2Vo8G8fcSTH/2GvkFm1NTeOyzHDlqV5LCKXY+gNX8U+Toot+TYux9QQ0Ro1D5T2152Sn86SARNyOsnOxSzf7I0+/sAfaCD2kjbNyZb5YWPNvezM9iMaJVgLhZmAZCUmnb9vBP9HXAgEm5E2pSUhdiaXSLcp3hnccbNsqQUlRejOCOixXPbIExiwguaqYg4XbGx9mnHTin6shHPVqfZ2MvTMjTEkf+S5+yMiXVa1Sjzt7q2iJcDoDAKu5RYrC/zxjZqlNxWzeMqHbeFARUA3eRaQwQ==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIFOjCCBCKgAwIBAgIQd/2aPtSfIJO8W8DTHLSRPTANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xIjAgBgNVBAMTGVZpc2EgZUNvbW1lcmNlIElzc3VpbmcgQ0EwHhcNMTYxMTAyMjAwNjIxWhcNMTgxMTAyMjAwNjIxWjBsMQ8wDQYDVQQHEwZNb3Njb3cxDzANBgNVBAgTBlJ1c3NpYTELMAkGA1UEBhMCUlUxEDAOBgNVBAoTB0JJTkJBTksxEDAOBgNVBAsTB0JJTkJBTksxFzAVBgNVBAMTDlZlcmlmaWVkQnlWaXNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7eXO8hN2IQh26zBkJ7zh4ckR3kTLK613smqmVggNJ4GweXHuMEhhlc+cYcOAO6pniMlzaWxDyexXg+2JSVrbvW15bsHYbYHaot2ZndOvvELL79SNe3pPv3vMuZLeXwJ4KNsV26/PIbK2Mc+Eo9FlkQbl5E1kY07N/5g4K/+/o7WjcsVizdp467AJebGduO9xYyQbG17SzXUjzwICBzBPRsgsan3PJuYctJjHbTIwoNnNr82ZYVkeRE7yOo/QroB5sDeNnVTgSOUYaM4qHbbGVUy3Zc+qyq4p6Km+EcKCRjxGpShPRZPKKvyHlUOgwlMk/oX7BQ4sDJ3EmnH1uaLVCQIDANfJo4IB0TCCAc0wZQYIKwYBBQUHAQEEWTBXMCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC52aXNhLmNvbS9vY3NwMC4GCCsGAQUFBzAChiJodHRwOi8vZW5yb2xsLnZpc2FjYS5jb20vZWNvbW0uY2VyMB8GA1UdIwQYMBaAFN/DKlUuL0I6ekCdkqD3R3nXj4eKMAwGA1UdEwEB/wQCMAAwgcoGA1UdHwSBwjCBvzAooCagJIYiaHR0cDovL0Vucm9sbC52aXNhY2EuY29tL2VDb21tLmNybDCBkqCBj6CBjIaBiWxkYXA6Ly9FbnJvbGwudmlzYWNhLmNvbTozODkvY249VmlzYSBlQ29tbWVyY2UgSXNzdWluZyBDQSxjPVVTLG91PVZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uLG89VklTQT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0MA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUm3YBohISsKwqb9YvSJ3ponmhTyowOQYDVR0gBDIwMDAuBgVngQMBATAlMCMGCCsGAQUFBwIBFhdodHRwOi8vd3d3LnZpc2EuY29tL3BraTANBgkqhkiG9w0BAQsFAAOCAQEABJhweDeYad6xAwRkYEbh1aFNzjKA0U/pHcFHUx1EQlcMcdi0G3sl6TrVh9GMi5DIe4uuoH8d3uBPS/AOGtvo/9Qnx7O423bAKkD56G5xJZYGrgTeh97SbIRdsiltnECehCGfUdtyiAirWzs7kcWgmMFDaGjk/GPra7dAkfCTuH68zwv79ae/z855/xoqbyeXu/B1oJ0ccd1YFNa+HwKcgkjOPFWrL1MEMRFK986Ic7ipnoooKBe1PyQCUc0hIUZ52tKy2pbNp/JoxpspNO+XJvCe6fa5lxAht70/V2xIh1xXOv77dkgnWfMP3aNPoj+HhMpBudNcxlCqlnoG5rd2WQ==</X509Certificate><X509Certificate>MIIFGzCCBAOgAwIBAgIRANLvVGMwl5OFbHV13pkMjIUwDQYJKoZIhvcNAQEFBQAwazELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMRwwGgYDVQQDExNWaXNhIGVDb21tZXJjZSBSb290MB4XDTExMDMyMTE3MzMzN1oXDTIyMDYyMjIzMTYzN1owcTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMSIwIAYDVQQDExlWaXNhIGVDb21tZXJjZSBJc3N1aW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArkmC50Q+GkmQyZ29kKxp1d+nJ43JwXhGZ7aFF1PiM5SlCESQ22qV/lBA3wHYYP8i17/GQQYNBiF3u4r6juXIHFwjwvKyFMF6kmBYXvcQa8Pd75FC1n3ffIrhEj+ldbmxidzK0hPfYyXEZqDpHhkunmvD7qz1BEWKE7NUYVFREfopViflKiVZcYrHi7CJAeBNY7dygvmIMnHUeH4NtDS5qf/n9DQQffVyn5hJWi5PeB87nTlty8zdji2tj7nA2+Y3PLKRJU3y1IbchqGlnXqxaaKfkTLNsiZq9PTwKaryH+um3tXf5u4mulzRGOWh2U+Uk4LntmMFCb/LqJkWnUVe+wIDAQABo4IBsjCCAa4wHwYDVR0jBBgwFoAUFTiDDz8sP3AzHs1G/geMIODXw7cwEgYDVR0TAQH/BAgwBgEB/wIBADA5BgNVHSAEMjAwMC4GBWeBAwEBMCUwIwYIKwYBBQUHAgEWF2h0dHA6Ly93d3cudmlzYS5jb20vcGtpMIIBCwYDVR0fBIIBAjCB/zA2oDSgMoYwaHR0cDovL0Vucm9sbC52aXNhY2EuY29tL1Zpc2FDQWVDb21tZXJjZVJvb3QuY3JsMDygOqA4hjZodHRwOi8vd3d3LmludGwudmlzYWNhLmNvbS9jcmwvVmlzYUNBZUNvbW1lcmNlUm9vdC5jcmwwgYaggYOggYCGfmxkYXA6Ly9FbnJvbGwudmlzYWNhLmNvbTozODkvY249VmlzYSBlQ29tbWVyY2UgUm9vdCxvPVZJU0Esb3U9VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFN/DKlUuL0I6ekCdkqD3R3nXj4eKMA0GCSqGSIb3DQEBBQUAA4IBAQAl3lDasc/q3yjspKOIgONgNnAgX3JCOqFtapWU1LJHLVyV47RhgKV7/Kj2m3vYFsyp+Uwis4aQM6sA7w3CHoJoWDg6OjhWUuhoIbMNR8BnNmN+ic3+IG9rUm2eFNz8r/QoUDFRPQGFD/NtIqvx9m+hk+8p7HS8aLaOPxNjPzmes96qIjBD+n0xJSu+F+3gWx7b5B6qTHq3jsA5kji2K5pSLN+v/bJriS5GNkTLzLSSWLNaKQ8fPmhlJnO4Z1x9zuZTKsepiNDA6TrpUaYDyzR15aWiO+rdElFEjl8BhDtMVK+3ncfcFV7BVZ75CGp/gzopwUtT8ORhW3+o7jrfu7zK</X509Certificate><X509Certificate>MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8 bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Message>
</ThreeDSecure>
Validation xml signature
private void getSignature (String xmlDoc){
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlDoc));
Document doc = builder.parse(is);
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0) {
throw new Exception("Cannot find Signature element");
}
// Overwrite ID
NodeList elList = doc.getElementsByTagName("PARes");
if (elList != null && elList.getLength() > 0 && ((Element)elList.item(0)).hasAttribute("id")) {
Attr id = ((Element)elList.item(0)).getAttributeNode("id");
((Element)elList.item(0)).setIdAttributeNode(id, true);
}
DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), nl.item(0));
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
// Unmarshal the XMLSignature.
XMLSignature signature = factory.unmarshalXMLSignature(valContext);
// Validate the XMLSignature.
boolean coreValidity = signature.validate(valContext);
log.error("Validated :" + (coreValidity?"True":"False"));
} catch (Exception e){
log.error("Exception : "+e.getMessage());
}
}
public class X509KeySelector extends KeySelector {
public KeySelectorResult select(KeyInfo keyInfo,
KeySelector.Purpose purpose,
AlgorithmMethod method,
XMLCryptoContext context)
throws KeySelectorException {
Iterator ki = keyInfo.getContent().iterator();
while (ki.hasNext()) {
XMLStructure info = (XMLStructure) ki.next();
if (!(info instanceof X509Data))
continue;
X509Data x509Data = (X509Data) info;
Iterator xi = x509Data.getContent().iterator();
while (xi.hasNext()) {
Object o = xi.next();
if (!(o instanceof X509Certificate))
continue;
final PublicKey key = ((X509Certificate)o).getPublicKey();
// Make sure the algorithm is compatible
// with the method.
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
return new KeySelectorResult() {
public Key getKey() {
return key;
}
};
}
}
}
throw new KeySelectorException("No key found!");
}
private static boolean algEquals(String algURI, String algName) {
if ((algName.equalsIgnoreCase("DSA") &&
algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) ||
(algName.equalsIgnoreCase("RSA") &&
algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
return true;
} else {
return false;
}
}
Everything is ok, but I should check that public key is trusted.XML's signed by different issuers. I have jssecacerts which contain 14 root CA. How to verify that this public key was signed one of this CA. Thank you for your advices

I've found decision
private boolean checkServerTrusted(X509Certificate cert) throws KeySelectorException {
try {
final File file = new File("C:\\TMP\\jssecacerts");
InputStream inStream = new FileInputStream(file);
KeyStore keystore = KeyStore.getInstance("JKS");
//String password = "";
//keystore.load(inStream, password.toCharArray());
keystore.load(inStream, null);
X509Certificate[] certs = new X509Certificate[keystore.size()];
int i = 0;
Enumeration<String> alias = keystore.aliases();
while (alias.hasMoreElements()) {
certs[i++] = (X509Certificate) keystore.getCertificate(alias
.nextElement());
}
return validateKeyChain(cert, certs);
} catch (Exception e){
throw new KeySelectorException ("Key verify exception reason :"+ e.getMessage());
}
}
/**
* Validate keychain
* #param client is the client X509Certificate
* #param trustedCerts is Array containing all trusted X509Certificate
* #return true if validation until root certificate success, false otherwise
* #throws CertificateException
* #throws InvalidAlgorithmParameterException
* #throws NoSuchAlgorithmException
* #throws NoSuchProviderException
*/
private boolean validateKeyChain(X509Certificate client,
X509Certificate... trustedCerts) throws CertificateException,
InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchProviderException {
boolean found = false;
int i = trustedCerts.length;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
TrustAnchor anchor;
Set anchors;
CertPath path;
List list;
PKIXParameters params;
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
while (!found && i > 0) {
anchor = new TrustAnchor(trustedCerts[--i], null);
anchors = Collections.singleton(anchor);
list = Arrays.asList(new Certificate[] { client });
path = cf.generateCertPath(list);
params = new PKIXParameters(anchors);
params.setRevocationEnabled(false);
if (client.getIssuerDN().equals(trustedCerts[i].getSubjectDN())) {
try {
validator.validate(path, params);
if (isSelfSigned(trustedCerts[i])) {
// found root ca
found = true;
System.out.println("validating root" + trustedCerts[i].getSubjectX500Principal().getName());
} else if (!client.equals(trustedCerts[i])) {
// find parent ca
System.out.println("validating via:" + trustedCerts[i].getSubjectX500Principal().getName());
found = validateKeyChain(trustedCerts[i], trustedCerts);
}
} catch (CertPathValidatorException e) {
// validation fail, check next certificate in the trustedCerts array
}
}
}
return found;
}
/**
*
* #param cert is X509Certificate that will be tested
* #return true if cert is self signed, false otherwise
* #throws CertificateException
* #throws NoSuchAlgorithmException
* #throws NoSuchProviderException
*/
private boolean isSelfSigned(X509Certificate cert)
throws CertificateException, NoSuchAlgorithmException,
NoSuchProviderException {
try {
PublicKey key = cert.getPublicKey();
cert.verify(key);
return true;
} catch (SignatureException sigEx) {
return false;
} catch (InvalidKeyException keyEx) {
return false;
}
}

Related

SAML assertion signature validation, Expected and Actual digest does not match

I am trying to validate an assertion signature received from an IDP. It results in a failure with following error :
Verification failed for URI "#_7e59add4-11a0-415f-85a3-6f493110d198"
Expected Digest: PgSvwq0Jn6GLMHID20j1fT40VlhvdavKxEM3PtNUfLM=
Actual Digest: mDcfPO26UwGV/tt/JM20ADDDkGGODjd2CZn7dqqR5LM=
org.opensaml.xml.signature.SignatureValidator(SignatureValidator.java:77) -
Signature did not validate against the credential's key
following is the code I am using to validate :
public class SamlTest {
public static void main(String[] args) throws Exception {
// read the file
File file = new File("d://a.xml");
BufferedReader bf = new BufferedReader(new FileReader(file));
String str = null;
String samlStr = "";
while ((str = bf.readLine()) != null) {
samlStr += str;
}
Assertion assertion = SamlTest.unmarshall(samlStr);
//Always do Profile Validation before cryptographically verify the Signature
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
try {
profileValidator.validate(assertion.getSignature());
} catch (ValidationException e) {
System.out.println("ErrorString [Error in SAMLSignatureProfilValidation]");
}
Certificate certificate = SamlTest.getCertificate(assertion.getSignature());
BasicCredential verificationCredential = new BasicCredential();
verificationCredential.setPublicKey(certificate.getPublicKey());
SignatureValidator sigValidator = new SignatureValidator(verificationCredential);
try {
sigValidator.validate(assertion.getSignature());
} catch (ValidationException e) {
System.out.println("unable to validate");
}
}
private static Assertion unmarshall(String samlStr) throws Exception {
DefaultBootstrap.bootstrap();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = null;
docBuilder = documentBuilderFactory.newDocumentBuilder();
ByteArrayInputStream is = new ByteArrayInputStream(samlStr.getBytes());
Document document = null;
document = docBuilder.parse(is);
Element element = document.getDocumentElement();
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element);
return (Assertion) unmarshaller.unmarshall(element);
}
private static Certificate getCertificate(Signature signature) {
try {
X509Certificate certificate = signature.getKeyInfo().getX509Datas().get(0).getX509Certificates().get(0);
if (certificate != null) {
//Converts org.opensaml.xml.signature.X509Certificate to java.security.cert.Certificate
String lexicalXSDBase64Binary = certificate.getValue();
byte[] decoded = DatatypeConverter.parseBase64Binary(lexicalXSDBase64Binary);
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(decoded));
return cert;
} catch (CertificateException e) {
//this should never happen
System.out.println("SAML Signature issue");
return null;
}
}
return null; // TODO Auto-generated method stub
} catch (NullPointerException e) {
//Null certificates
return null;
}
}}
below is the assertion xml received : `
<?xml version="1.0" encoding="UTF-8" standalone="no"?><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns10="urn:oasis:names:tc:SAML:2.0:conditions:delegation" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ns3="http://www.rsa.com/names/2009/12/std-ext/WS-Trust1.4/advice" xmlns:ns4="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ns5="http://www.w3.org/2000/09/xmldsig#" xmlns:ns6="http://www.rsa.com/names/2009/12/std-ext/SAML2.0" xmlns:ns7="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns8="http://docs.oasis-open.org/ws-sx/ws-trust/200802" xmlns:ns9="http://www.w3.org/2005/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_7e59add4-11a0-415f-85a3-6f493110d198" IssueInstant="2015-06-16T19:38:03.664Z" Version="2.0"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://localhost/websso/SAML2/Metadata/vsphere.local</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#_7e59add4-11a0-415f-85a3-6f493110d198"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs xsi"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>PgSvwq0Jn6GLMHID20j1fT40VlhvdavKxEM3PtNUfLM=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>ovoMj6mUzEnhayptgu3MwQOiBEs47GO8Xs/H02SgO8/881X5m7anAmS8yIjHiOTu3Q0kNJH1K2cQ
uBNxKQG75jPHbM3wF6XVKLbcyjAWHjtg3Ndz6F2spIP13LZ7LM2KUBcwGh9YWBnybJWxwr70+qj0
7xHO5wEnV3RpkQPCjMgAfnesEAEHoCGpnQNQu0twSffWzKLKZcg6PHS2g49WY1r65Sw5Jcy9/VdN
4/mtEuNa4fb0wNbaKcpPxsjUo7dbeMdbZxl5T0E2pOTzGJkRKVfw1P6Vd2qIFrORVpfni5LAYkET
GJA40iY7wfVLJflIX7+9QcIEtMKsL5rbtxvQpQ==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDcDCCAligAwIBAgIJAMGuXxNnFfBZMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNVBAMMAkNBMRcw
FQYKCZImiZPyLGQBGRYHdnNwaGVyZTEVMBMGCgmSJomT8ixkARkWBWxvY2FsMQswCQYDVQQGEwJV
UzEQMA4GA1UECgwHcnVjaGF2YzAeFw0xNTAyMTcxNjMzNTFaFw0yNTAyMTExNjQzNDJaMBgxFjAU
BgNVBAMMDXNzb3NlcnZlclNpZ24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqV+/l
kSS9U2y6RBsLiqxwdiLjJJFCw/3iFu/Fmpu8vltMNPE5ryZsT87HJGzK8jDgGoTcD0DbbUk7+Sbe
XGVj7n5ZsBXiTt8nbpWQkUfBcNxKimqkGm3WgRgF3UjtNt4enC+mOLw4/aicBvvuscd8ur1QyJxK
zTUVOtkKFYg1FuKaelkSA2GrScLBzjaU99L0K2YrWncKG2T+1yIK5Md4TPr4X3GwhEqlBn7YK2sJ
43ILrEu43BCGyhkawp3bOHhnMVzMUHi2eY4NLXj0ZNTUFRrl8LKpDlSqFwL7ChNuhfLJOlncDwvD
20gOa6TWEC8qr3hXo4u5vUx9j2e5PS/pAgMBAAGjeTB3MAsGA1UdDwQEAwIF4DAoBgNVHREEITAf
gh1ydWNoYXZjLnRlc3RsYWIuY29tbXZhdWx0LmNvbTAdBgNVHQ4EFgQUjBP2wdHo83NDTsksTBtf
/1+EwA4wHwYDVR0jBBgwFoAU++fsPhJCQ4XETaWO1bQCjDDAgM8wDQYJKoZIhvcNAQELBQADggEB
AD4WqxL4+y4Uz/IzrKljq8mpU+dZNqpni8u5RaPUa4z/abfpB/vgSD08WGo7FHOYKDVJK6ScE8wB
+cuUV0/rL+4/L1sUVj4hixH/fUVS6jO6/SZerHEZ0ubO/X5zZAyfWXOKvxa6llgNFYjKGqd74+Lh
LCB2w84/VOOOJlaBJFFbh/9AY8cwtd8jFnMAYmQE7YQSLEagIKoeQSiVO1H8Kbhs4EQtLVmEQjR9
Pt1/H8VsRtPs+/0vAbzq8DJ6FTMz+OuhpyJHmIdP2Xw8T/2LGpGFSTVzbeGKGW3h7cCHA0MEHQ2J
ags26hB/IvRy2PxLgA9yRUroro9dbW8jIGch4UM=</ds:X509Certificate><ds:X509Certificate>MIIDgDCCAmigAwIBAgIJAP828FCXHTizMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNVBAMMAkNBMRcw
FQYKCZImiZPyLGQBGRYHdnNwaGVyZTEVMBMGCgmSJomT8ixkARkWBWxvY2FsMQswCQYDVQQGEwJV
UzEQMA4GA1UECgwHcnVjaGF2YzAeFw0xNTAyMTQxNjQzNDJaFw0yNTAyMTExNjQzNDJaMFwxCzAJ
BgNVBAMMAkNBMRcwFQYKCZImiZPyLGQBGRYHdnNwaGVyZTEVMBMGCgmSJomT8ixkARkWBWxvY2Fs
MQswCQYDVQQGEwJVUzEQMA4GA1UECgwHcnVjaGF2YzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALgcEKO2qkQobx4vGXNG2D6HqnHNwiqEBs+cbrAGRwVtT2AxavMu4aUL9kDO8yyrqXT2
UF5W5B2jFEWr413h8MmV4v+F/+MqVW7UXQ6C0f6bsaBLdmQNa69b4EAj0UGvvohogObglvP9Du0n
qXwDTt3NMg2aJefHtLsyAXA6A1IR85g/AdImBezM0ZgUALpf1Jaq3XjZvR9XqRiu/VZHDEJacxep
/Csw9AuLA5D2U8bWBV8URoBIfFzyho+3dYG8zS1l9Ym5CvSP98nryWSH1LwsEBVunoZpVE+TLGsz
A4uui1/y31gO04y44DxZp1Bh/HfIT4woOIOIlBqOGd5Rz+kCAwEAAaNFMEMwHQYDVR0OBBYEFPvn
7D4SQkOFxE2ljtW0AowwwIDPMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMA0G
CSqGSIb3DQEBCwUAA4IBAQBcRs/wwAfkWVbwgVKkucSMnRNb7kPS7qERcUykMGA/46QXhDcDShd1
j2aXbZKx0DNLKpGYuIN4N6uGdHZu0jABaSMOtVYdXCAHdXGPYJB6vV/l3jOOVvOPULwaf8lbBrmM
AuR6F6J1DBiXH+XMuOPB6/Tp9YYSoFJkPqhxqxyns3tjjTXmCIcoEUuPqACniLk6aUzlKFzDUt2N
hp34Qzj4BdH7QepHjR/mcDkVVaMjY597d2f/kAJm0D/l01W3nyKCbDb3yq3w8f6gj1WIIB6o8w9R
HsZwm4eVFYhJWWvi9N2wci8X5PMdDi/abUxhOT7EYEQGk39dfc/VTEQoMKrE</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject><saml2:NameID Format="http://schemas.xmlsoap.org/claims/UPN">Administrator</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"><saml2:NameID Format="http://schemas.xmlsoap.org/claims/UPN">vsphere-webclient-21665f80-b6c4-11e4-b9fe-005056a638d3#vsphere.local</saml2:NameID><saml2:SubjectConfirmationData xsi:type="saml2:KeyInfoConfirmationDataType"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIID5TCCAs2gAwIBAgIJAMk0TrGWNX/vMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNVBAMMAkNBMRcw
FQYKCZImiZPyLGQBGRYHdnNwaGVyZTEVMBMGCgmSJomT8ixkARkWBWxvY2FsMQswCQYDVQQGEwJV
UzEQMA4GA1UECgwHcnVjaGF2YzAeFw0xNTAyMTcxNjM1MDhaFw0yNTAyMTExNjQzNDJaMIGMMRow
GAYDVQQDDBF2c3BoZXJlLXdlYmNsaWVudDEXMBUGCgmSJomT8ixkARkWB3ZzcGhlcmUxFTATBgoJ
kiaJk/IsZAEZFgVsb2NhbDELMAkGA1UEBhMCVVMxMTAvBgNVBAsMKG1JRC0yMTY2NWY4MC1iNmM0
LTExZTQtYjlmZS0wMDUwNTZhNjM4ZDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA
zkp7RK+aOZqq4+yyp/gfsLr4jQnOiLCNGdvEeLXVhUPWogYl0MkHEt3DY6i2HqL0xmmPeRjmOJ1T
62eR3Nc8ugrapKUy7bYgCTT6rzvjU7KtzHg/SncuwncrB53//lSndJ41UtTWNxZSqqja3tmfg3pT
4EQkv0YiyEeayKJhfNz6XiuL12wdBvai0SIEFIsZTq92hNlTs4W58tT8ov6408BEMtRcTVHrOSAS
BS2waelqHAt141PWos3ynz4MUsxRs2p0T77K+wh2Mj/eWQgJJnVVuc4oVA1uLOQHjP777QV/gEkd
p6v42q8b+24LtTWJssMIVvmsmvoEtItDbpApAgMBAAGjeTB3MAsGA1UdDwQEAwIF4DAoBgNVHREE
ITAfgh1ydWNoYXZjLnRlc3RsYWIuY29tbXZhdWx0LmNvbTAdBgNVHQ4EFgQUHR0Ta1eFnWxSD37T
ZFPQncCZYlswHwYDVR0jBBgwFoAU++fsPhJCQ4XETaWO1bQCjDDAgM8wDQYJKoZIhvcNAQELBQAD
ggEBAETECKs16qfadNvLwNysQq5F9Y9pAhnss6PniRLdQ2D7dbKgLNjgi4CIEV3SuaDXaqONV9IV
+IjAg6N+yMqGghc64MyAzDS0Rkp2R7hfNjyYUcG9lNTSpsKSZE0iNb9RWaqrPKu4RsnPvjIStx43
EytkF63Q7ktYxFCXlnB9AVeMa6nfOzFZS+SXHrd+zWs62Hp/9mBHLoHKEYYQawpJlbBnAkg8WZxq
uVE/Ky5Gv8ni3eAovM2g0Ot7gqqbfPH09Yk4L9pBUPw/lT2icBvZ6yHgWxmEnZuHBKUF5B8F0smI
TSCwNY2lUghkxxCdTEaqsthPGb9uYEB6JFJDgblgEBg=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></saml2:SubjectConfirmationData></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2015-06-16T19:38:51.295Z" NotOnOrAfter="2015-07-16T19:38:51.295Z"><saml2:ProxyRestriction Count="9"/><saml2:Condition xmlns:del="urn:oasis:names:tc:SAML:2.0:conditions:delegation" xsi:type="del:DelegationRestrictionType"><del:Delegate DelegationInstant="2015-06-16T19:36:37.101Z"><saml2:NameID Format="http://schemas.xmlsoap.org/claims/UPN">vsphere-webclient-21665f80-b6c4-11e4-b9fe-005056a638d3#vsphere.local</saml2:NameID></del:Delegate></saml2:Condition><saml2:Condition xmlns:rsa="http://www.rsa.com/names/2009/12/std-ext/SAML2.0" Count="9" xsi:type="rsa:RenewRestrictionType"/></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2015-06-16T19:38:03.662Z"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute FriendlyName="givenName" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">Administrator</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="Groups" Name="http://rsa.com/schemas/attr-names/2009/01/GroupIdentity" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">SophosAdministrator</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">Administrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.localAdministrators</saml2:AttributeValue><saml2:AttributeValue xsi:type="xs:string">vsphere.localEveryone</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="Subject Type" Name="http://vmware.com/schemas/attr-names/2011/07/isSolution" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string">false</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="surname" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xsi:type="xs:string"/></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion>
`could someone please help me find the issue here.

How to accept mine if any conflicts occur while pull-rebase in JGit

I have a piece of code that does pull with rebase:
private void pullWithRebase(Git git) throws GitAPIException {
git.checkout().setName("master").call();
List<Ref> branches = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
String remoteMasterBranchName = "refs/remotes/origin/master";
for (Ref ref : branches) {
if (remoteMasterBranchName.equals(ref.getName())) {
PullResult result = git.pull().setRemoteBranchName("master").setRebase(true).call();
return;
}
}
}
However it doesn't work if any conflicts occur while merging. If they do occur, I want to accept mine
I ended up just merging two branches and directly resolving any conflicts by modifying files.
private static final String CONFLICT_HEAD_MARKER = "<<<<<<<";
private static final String CONFLICT_BORDER_MARKER = "=======";
private static final String CONFLICT_UPSTREAM_MARKER = ">>>>>>>";
private boolean acceptHead;
public void resolve(File file) throws IOException {
File temp = new File(file.getParent(), "temp" + System.currentTimeMillis());
try(BufferedReader reader = new BufferedReader(new FileReader(file));
BufferedWriter writer = new BufferedWriter(new FileWriter(temp))) {
String currentLine;
boolean removePartition = false;
while((currentLine = reader.readLine()) != null) {
if (currentLine.contains(CONFLICT_HEAD_MARKER)) {
removePartition = !acceptHead;
continue;
} else if (currentLine.contains(CONFLICT_BORDER_MARKER)) {
removePartition = acceptHead;
continue;
} else if (currentLine.contains(CONFLICT_UPSTREAM_MARKER)) {
removePartition = false;
continue;
}
if (!removePartition) {
writer.write(currentLine + System.getProperty("line.separator"));
}
}
}
FileUtils.forceDelete(file);
FileUtils.moveFile(temp, file);
}

ServiceStack REST API path variables from root throwing exception

I am trying to write a REST web service using ServiceStack that accepts variable paths off of route. For example:
[Route("/{group}"]
public class Entity : IReturn<SomeType> {}
This throws a NotSupported Exception "RestPath '/{collection}' on type Entity is not supported". However, if I change the path as follows (along with the associated path in AppHost configuration) to:
[Route("/rest/{group}"]
It works just fine. In order to integrate with the system that I am working with, I need to use /{group}.
ServiceStack now allows you to add a fallback route from the / root path to handle any un-matched requests, that's not handled by a catch-all handler or refers to an existing static file. So in v3.9.56 you can now do:
[FallbackRoute("/{group}"]
public class Entity : IReturn<SomeType> {}
An alternative option is to register a IAppHost.CatchAllHandlers to handle un-matched routes, but you would need to return your own IHttpHandler to handle the request or alternatively return a RedirectHttpHandler to redirect to a different route that is managed by ServiceStack.
My current work in progress, a plugin to serve the default page to all 'not found' routes without changing the url in the browser, includes most of what you'll need to handle a global wildcard route. Use it to get you started.
To understand what this code is doing, it helps to understand ServiceStack's routing priority, and how CatchAllHandlers fit into the process. ServiceStack calls ServiceStackHttpHandlerFactory.GetHandler to get the handler for the current route.
ServiceStackHttpHandlerFactory.GetHandler returns:
A matching RawHttpHandler, if any.
If the domain root, the handler returned by GetCatchAllHandlerIfAny(...), if any.
If the route matches a metadata uri (I'm skipping over the exact logic here, as it's not important for your question), the relevant handler, if any.
The handler returned by ServiceStackHttpHandlerFactory.GetHandlerForPathInfo if any.
NotFoundHandler.
ServiceStackHttpHandlerFactory.GetHandlerForPathInfo returns:
If the url matches a valid REST route, a new RestHandler.
If the url matches an existing file or directory, it returns
the handler returned by GetCatchAllHandlerIfAny(...), if any.
If it's a supported filetype, a StaticFileHandler,
If it's not a supported filetype, the ForbiddenHttpHandler.
The handler returned by GetCatchAllHandlerIfAny(...), if any.
null.
The CatchAllHandlers array contains functions that evaluate the url and either return a handler, or null. The functions in the array are called in sequence and the first one that doesn't return null handles the route. Let me highlight some key elements:
First, the plugin adds a CatchAllHandler to the appHost.CatchAllHandlers array when registered.
public void Register(IAppHost appHost)
{
appHost.CatchAllHandlers.Add((string method, string pathInfo, string filepath) =>
Factory(method, pathInfo, filepath));
}
Second, the CatchAllHandler. As described above, the function may be called for the domain root, an existing file or directory, or any other unmatched route. Your method should return a handler, if your criteria are met, or return null.
private static Html5ModeFeature Factory(String method, String pathInfo, String filepath)
{
var Html5ModeHandler = Html5ModeFeature.Instance;
List<string> WebHostRootFileNames = RootFiles();
// handle domain root
if (string.IsNullOrEmpty(pathInfo) || pathInfo == "/")
{
return Html5ModeHandler;
}
// don't handle 'mode' urls
var mode = EndpointHost.Config.ServiceStackHandlerFactoryPath;
if (mode != null && pathInfo.EndsWith(mode))
{
return null;
}
var pathParts = pathInfo.TrimStart('/').Split('/');
var existingFile = pathParts[0].ToLower();
var catchAllHandler = new Object();
if (WebHostRootFileNames.Contains(existingFile))
{
var fileExt = Path.GetExtension(filepath);
var isFileRequest = !string.IsNullOrEmpty(fileExt);
// don't handle directories or files that have another handler
catchAllHandler = GetCatchAllHandlerIfAny(method, pathInfo, filepath);
if (catchAllHandler != null) return null;
// don't handle existing files under any event
return isFileRequest ? null : Html5ModeHandler;
}
// don't handle non-physical urls that have another handler
catchAllHandler = GetCatchAllHandlerIfAny(method, pathInfo, filepath);
if (catchAllHandler != null) return null;
// handle anything else
return Html5ModeHandler;
}
In the case of the wildcard at the root domain, you may not want to hijack routes that can be handled by another CatchAllHandler. If so, to avoid infinite recursion, you'll need a custom GetCatchAllHandlerIfAny method.
//
// local copy of ServiceStackHttpHandlerFactory.GetCatchAllHandlerIfAny, prevents infinite recursion
//
private static IHttpHandler GetCatchAllHandlerIfAny(string httpMethod, string pathInfo, string filePath)
{
if (EndpointHost.CatchAllHandlers != null)
{
foreach (var httpHandlerResolver in EndpointHost.CatchAllHandlers)
{
if (httpHandlerResolver == Html5ModeFeature.Factory) continue; // avoid infinite recursion
var httpHandler = httpHandlerResolver(httpMethod, pathInfo, filePath);
if (httpHandler != null)
return httpHandler;
}
}
return null;
}
Here's the complete, and completely untested, plugin. It compiles. It carries no warranty of fitness for any specific purpose.
using ServiceStack;
using ServiceStack.Common.Web;
using ServiceStack.Razor;
using ServiceStack.ServiceHost;
using ServiceStack.Text;
using ServiceStack.WebHost.Endpoints;
using ServiceStack.WebHost.Endpoints.Formats;
using ServiceStack.WebHost.Endpoints.Support;
using ServiceStack.WebHost.Endpoints.Support.Markdown;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
namespace MyProject.Support
{
public enum DefaultFileFormat
{
Markdown,
Razor,
Static
}
public class Html5ModeFeature : EndpointHandlerBase, IPlugin
{
private FileInfo fi { get; set; }
private DefaultFileFormat FileFormat { get; set; }
private DateTime FileModified { get; set; }
private byte[] FileContents { get; set; }
public MarkdownHandler Markdown { get; set; }
public RazorHandler Razor { get; set; }
public object Model { get; set; }
private static Dictionary<string, string> allDirs;
public string PathInfo { get; set; }
public void Register(IAppHost appHost)
{
appHost.CatchAllHandlers.Add((string method, string pathInfo, string filepath) =>
Factory(method, pathInfo, filepath));
}
private Html5ModeFeature()
{
foreach (var defaultDoc in EndpointHost.Config.DefaultDocuments)
{
if (PathInfo == null)
{
var defaultFileName = Path.Combine(Directory.GetCurrentDirectory(), defaultDoc);
if (!File.Exists(defaultFileName)) continue;
PathInfo = (String)defaultDoc; // use first default document found.
}
}
SetFile();
}
private static Html5ModeFeature instance;
public static Html5ModeFeature Instance
{
get { return instance ?? (instance = new Html5ModeFeature()); }
}
public void SetFile()
{
if (PathInfo.EndsWith(MarkdownFormat.MarkdownExt) || PathInfo.EndsWith(MarkdownFormat.TemplateExt))
{
Markdown = new MarkdownHandler(PathInfo);
FileFormat = DefaultFileFormat.Markdown;
return;
}
if (PathInfo.EndsWith(Razor.RazorFormat.RazorFileExtension)) {
Razor = new RazorHandler(PathInfo);
FileFormat = DefaultFileFormat.Razor;
return;
}
FileContents = File.ReadAllBytes(PathInfo);
FileModified = File.GetLastWriteTime(PathInfo);
FileFormat = DefaultFileFormat.Static;
}
//
// ignore request.PathInfo, return default page, extracted from StaticFileHandler.ProcessResponse
//
public void ProcessStaticPage(IHttpRequest request, IHttpResponse response, string operationName)
{
response.EndHttpHandlerRequest(skipClose: true, afterBody: r =>
{
TimeSpan maxAge;
if (r.ContentType != null && EndpointHost.Config.AddMaxAgeForStaticMimeTypes.TryGetValue(r.ContentType, out maxAge))
{
r.AddHeader(HttpHeaders.CacheControl, "max-age=" + maxAge.TotalSeconds);
}
if (request.HasNotModifiedSince(fi.LastWriteTime))
{
r.ContentType = MimeTypes.GetMimeType(PathInfo);
r.StatusCode = 304;
return;
}
try
{
r.AddHeaderLastModified(fi.LastWriteTime);
r.ContentType = MimeTypes.GetMimeType(PathInfo);
if (fi.LastWriteTime > this.FileModified)
SetFile(); //reload
r.OutputStream.Write(this.FileContents, 0, this.FileContents.Length);
r.Close();
return;
}
catch (Exception ex)
{
throw new HttpException(403, "Forbidden.");
}
});
}
private void ProcessServerError(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
{
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine("\"ResponseStatus\":{");
sb.AppendFormat(" \"ErrorCode\":{0},\n", 500);
sb.AppendFormat(" \"Message\": HTML5ModeHandler could not serve file {0}.\n", PathInfo.EncodeJson());
sb.AppendLine("}");
sb.AppendLine("}");
httpRes.EndHttpHandlerRequest(skipClose: true, afterBody: r =>
{
r.StatusCode = 500;
r.ContentType = ContentType.Json;
var sbBytes = sb.ToString().ToUtf8Bytes();
r.OutputStream.Write(sbBytes, 0, sbBytes.Length);
r.Close();
});
return;
}
private static List<string> RootFiles()
{
var WebHostPhysicalPath = EndpointHost.Config.WebHostPhysicalPath;
List<string> WebHostRootFileNames = new List<string>();
foreach (var filePath in Directory.GetFiles(WebHostPhysicalPath))
{
var fileNameLower = Path.GetFileName(filePath).ToLower();
WebHostRootFileNames.Add(Path.GetFileName(fileNameLower));
}
foreach (var dirName in Directory.GetDirectories(WebHostPhysicalPath))
{
var dirNameLower = Path.GetFileName(dirName).ToLower();
WebHostRootFileNames.Add(Path.GetFileName(dirNameLower));
}
return WebHostRootFileNames;
}
private static Html5ModeFeature Factory(String method, String pathInfo, String filepath)
{
var Html5ModeHandler = Html5ModeFeature.Instance;
List<string> WebHostRootFileNames = RootFiles();
// handle domain root
if (string.IsNullOrEmpty(pathInfo) || pathInfo == "/")
{
return Html5ModeHandler;
}
// don't handle 'mode' urls
var mode = EndpointHost.Config.ServiceStackHandlerFactoryPath;
if (mode != null && pathInfo.EndsWith(mode))
{
return null;
}
var pathParts = pathInfo.TrimStart('/').Split('/');
var existingFile = pathParts[0].ToLower();
var catchAllHandler = new Object();
if (WebHostRootFileNames.Contains(existingFile))
{
var fileExt = Path.GetExtension(filepath);
var isFileRequest = !string.IsNullOrEmpty(fileExt);
// don't handle directories or files that have another handler
catchAllHandler = GetCatchAllHandlerIfAny(method, pathInfo, filepath);
if (catchAllHandler != null) return null;
// don't handle existing files under any event
return isFileRequest ? null : Html5ModeHandler;
}
// don't handle non-physical urls that have another handler
catchAllHandler = GetCatchAllHandlerIfAny(method, pathInfo, filepath);
if (catchAllHandler != null) return null;
// handle anything else
return Html5ModeHandler;
}
//
// Local copy of private StaticFileHandler.DirectoryExists
//
public static bool DirectoryExists(string dirPath, string appFilePath)
{
if (dirPath == null) return false;
try
{
if (!ServiceStack.Text.Env.IsMono)
return Directory.Exists(dirPath);
}
catch
{
return false;
}
if (allDirs == null)
allDirs = CreateDirIndex(appFilePath);
var foundDir = allDirs.ContainsKey(dirPath.ToLower());
//log.DebugFormat("Found dirPath {0} in Mono: ", dirPath, foundDir);
return foundDir;
}
//
// Local copy of private StaticFileHandler.CreateDirIndex
//
static Dictionary<string, string> CreateDirIndex(string appFilePath)
{
var indexDirs = new Dictionary<string, string>();
foreach (var dir in GetDirs(appFilePath))
{
indexDirs[dir.ToLower()] = dir;
}
return indexDirs;
}
//
// Local copy of private StaticFileHandler.GetDirs
//
static List<string> GetDirs(string path)
{
var queue = new Queue<string>();
queue.Enqueue(path);
var results = new List<string>();
while (queue.Count > 0)
{
path = queue.Dequeue();
try
{
foreach (string subDir in Directory.GetDirectories(path))
{
queue.Enqueue(subDir);
results.Add(subDir);
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
return results;
}
//
// local copy of ServiceStackHttpHandlerFactory.GetCatchAllHandlerIfAny, prevents infinite recursion
//
private static IHttpHandler GetCatchAllHandlerIfAny(string httpMethod, string pathInfo, string filePath)
{
if (EndpointHost.CatchAllHandlers != null)
{
foreach (var httpHandlerResolver in EndpointHost.CatchAllHandlers)
{
if (httpHandlerResolver == Html5ModeFeature.Factory) continue; // avoid infinite recursion
var httpHandler = httpHandlerResolver(httpMethod, pathInfo, filePath);
if (httpHandler != null)
return httpHandler;
}
}
return null;
}
public override void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
{
switch (FileFormat)
{
case DefaultFileFormat.Markdown:
{
Markdown.ProcessRequest(httpReq, httpRes, operationName);
break;
}
case DefaultFileFormat.Razor:
{
Razor.ProcessRequest(httpReq, httpRes, operationName);
break;
}
case DefaultFileFormat.Static:
{
fi.Refresh();
if (fi.Exists) ProcessStaticPage(httpReq, httpRes, operationName); else ProcessServerError(httpReq, httpRes, operationName);
break;
}
default:
{
ProcessServerError(httpReq, httpRes, operationName);
break;
}
}
}
public override object CreateRequest(IHttpRequest request, string operationName)
{
return null;
}
public override object GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, object request)
{
return null;
}
}
}

Huge amount of packet drops and latency faced in netty

I am using netty 3.5.11 with Jdk 1.7 on Ubuntu to receive a large amount of updates of stocks rates at a very high frequency. The message format being sent is JSON. The data is subscribed from topic on a redis server. There is a Subscriber for each symbol. The channel object is passed to multiple Subscribers and on receiving the data it is written to the client.
Now the amount of data received is around 25,000 records in 2 minutes. Each record size is on an average around 500 bytes long.
During test runs around 7500/8000 records were dropped because the channel was not writable.
How do i avoid this. ?
I also noticed that the latency increases systematically leading to updates being received after a long period. This happened when i I used Bufferedwritehandler to avoid packet drops.
Here are the options that i set on bootstrap.
executionHandler = new ExecutionHandler(
new OrderedMemoryAwareThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, 1000000, 10000000, 100,
TimeUnit.MILLISECONDS));
serverBootStrap.setPipelineFactory(new ChannelPipelineFactory()
{
#Override
public ChannelPipeline getPipeline() throws Exception
{
return Channels.pipeline(new PortUnificationServerHandler(getConfiguration(), executionHandler));
}
});
serverBootStrap.setOption("child.tcpNoDelay", true);
serverBootStrap.setOption("tcpNoDelay", true);
serverBootStrap.setOption("child.keepAlive", true);
serverBootStrap.setOption("child.reuseAddress", true);
//setting buffer size can improve I/O
serverBootStrap.setOption("child.sendBufferSize", 16777216);
serverBootStrap.setOption("receiveBufferSize", 16777216);//1048576);
// better to have an receive buffer predictor
serverBootStrap.setOption("receiveBufferSizePredictorFactory", new AdaptiveReceiveBufferSizePredictorFactory(1024, 1024 * 16, 16777216));//1048576));
//if the server is sending 1000 messages per sec, optimum write buffer water marks will
//prevent unnecessary throttling, Check NioSocketChannelConfig doc
serverBootStrap.setOption("backlog", 1000);
serverBootStrap.setOption("sendBufferSize", 16777216);//1048576);
serverBootStrap.setOption("writeBufferLowWaterMark", 1024 * 1024 * 25);
serverBootStrap.setOption("writeBufferHighWaterMark", 1024 * 1024 * 50);
The pipeline and handlers class
public class PortUnificationServerHandler extends FrameDecoder
{
private AppConfiguration appConfiguration;
private final ExecutionHandler executionHandler;
public PortUnificationServerHandler(AppConfiguration pAppConfiguration, ExecutionHandler pExecutionHandler)
{
appConfiguration = pAppConfiguration;
this.executionHandler = pExecutionHandler;
}
#Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception
{
String lRequest = buffer.toString(CharsetUtil.UTF_8);
if (ConnectionServiceHelper.isValidJSON(lRequest))
{
ObjectMapper lObjectMapper = new ObjectMapper();
StringReader lStringReader = new StringReader(lRequest);
JsonNode lNode = lObjectMapper.readTree(lStringReader);
if (lNode.get(Constants.REQUEST_TYPE).asText().trim().equalsIgnoreCase(Constants.LOGIN_REQUEST))
{
JsonNode lDataNode1 = lNode.get(Constants.REQUEST_DATA);
LoginRequest lLogin = lObjectMapper.treeToValue(lDataNode1, LoginRequest.class);
if (lLogin.getCompress() != null)
{
if (lLogin.getCompress().trim().equalsIgnoreCase(Constants.COMPRESS_FLAG_TRUE))
{
enableJSON(ctx);
enableGzip(ctx);
ctx.getPipeline().remove(this);
}
else
{
enableJSON(ctx);
ctx.getPipeline().remove(this);
}
}
else
{
enableJSON(ctx);
ctx.getPipeline().remove(this);
}
}
}
// Forward the current read buffer as is to the new handlers.
return buffer.readBytes(buffer.readableBytes());
}
private void enableJSON(ChannelHandlerContext ctx)
{
ChannelPipeline pipeline = ctx.getPipeline();
boolean lHandlerExists = pipeline.getContext("bufferedwriter") != null;
if (!lHandlerExists)
{
pipeline.addFirst("bufferedwriter", new MyBufferedWriteHandler()); // 80960
}
boolean lHandlerExists = pipeline.getContext("framer") != null;
if (!lHandlerExists)
{
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(65535,
new ChannelBuffer[]
{
ChannelBuffers.wrappedBuffer(
new byte[]
{
'\n'
})
}));
}
lHandlerExists = pipeline.getContext("decoder") != null;
if (!lHandlerExists)
{
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
}
lHandlerExists = pipeline.getContext("encoder") != null;
if (!lHandlerExists)
{
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
}
lHandlerExists = pipeline.getContext("executor") != null;
if (!lHandlerExists)
{
pipeline.addLast("executor", executionHandler);
}
lHandlerExists = pipeline.getContext("handler") != null;
if (!lHandlerExists)
{
pipeline.addLast("handler", new ConnectionServiceUpStreamHandler(appConfiguration));
}
lHandlerExists = pipeline.getContext("unite") != null;
if (!lHandlerExists)
{
pipeline.addLast("unite", new PortUnificationServerHandler(appConfiguration, executionHandler));
}
}
private void enableGzip(ChannelHandlerContext ctx)
{
ChannelPipeline pipeline = ctx.getPipeline();
//pipeline.remove("decoder");
//pipeline.addLast("decoder", new MyStringDecoder(CharsetUtil.UTF_8, true));
//pipeline.addLast("compress", new CompressionHandler(80, "gzipdeflater"));
boolean lHandlerExists = pipeline.getContext("encoder") != null;
if (lHandlerExists)
{
pipeline.remove("encoder");
}
lHandlerExists = pipeline.getContext("gzipdeflater") != null;
if (!lHandlerExists)
{
pipeline.addBefore("executor", "gzipdeflater", new ZlibEncoder(ZlibWrapper.GZIP));
}
lHandlerExists = pipeline.getContext("lengthprepender") != null;
if (!lHandlerExists)
{
pipeline.addAfter("gzipdeflater", "lengthprepender", new LengthFieldPrepender(4));
}
}
}
The BufferedWriterHandler
public class MyBufferedWriteHandler extends BufferedWriteHandler
{
private final AtomicLong bufferSize = new AtomicLong();
final Logger logger = LoggerFactory.getLogger(getClass());
public MyBufferedWriteHandler() {
// Enable consolidation by default.
super(true);
}
#Override
public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception
{
ChannelBuffer data = (ChannelBuffer) e.getMessage();
if (e.getChannel().isWritable())
{
long newBufferSize = bufferSize.get();
// Flush the queue if it gets larger than 8KiB.
if (newBufferSize > 0)
{
flush();
bufferSize.set(0);
}
ctx.sendDownstream(e);
}
else
{
logger.warn( "Buffering data for : " + e.getChannel().getRemoteAddress() );
super.writeRequested(ctx, e);
bufferSize.addAndGet(data.readableBytes());
}
}
#Override
public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
{
if (e.getChannel().isWritable())
{
flush();
}
}
The function used in the Subscriber class to write data
public void writeToClient(Channel pClientChannel, String pMessage) throws IOException
{
String lMessage = pMessage;
if (pClientChannel.isWritable())
{
lMessage += Constants.RESPONSE_DELIMITER;
pClientChannel.write(lMessage);
}
else
{
logger.warn(DroppedCounter++ + " droppped : " + pMessage);
}
}
I have implemented some of the suggestions that i read on stackoverflow and other sites. But i have not been successfull in resolving this issue.
Kindly suggest or advice as to what am i missing ?
Thanks

Create Multimedia component with Metadata fields.using core service

I am creating Multimedia components using core service and everything is working fine. But when Metadata schema fields are defined on the Multimedia schema using which I am creating my Multimedia components then I am getting following error:-
Unable to find http://www.tridion.com/ContentManager/5.0/DefaultMultimediaSchema:Metadata.
This message is displayed when I have given Default Multimedia schema's TCM ID for Multimedia component. As metadata fields are saved in Tridion Database so I first have to retrieve these fields from broker or what is the best solution for this, please suggest. Below is the sample code. Please modify it if someone have any idea for providing default value for metadatafields and how to retrieve them (with/without querying broker DB):-
public static string UploadMultiMediaComponent(string folderUri, string title, string schemaID)
{
core_service.ServiceReference1.SessionAwareCoreService2010Client client = new SessionAwareCoreService2010Client();
client.ClientCredentials.Windows.ClientCredential.UserName = "myUserName";
client.ClientCredentials.Windows.ClientCredential.Password = "myPassword"; client.Open();
ComponentData multimediaComponent = (ComponentData)client.GetDefaultData(
ItemType.Component, folderUri);
multimediaComponent.Title = title;
multimediaComponent.ComponentType = ComponentType.Multimedia;
multimediaComponent.Schema.IdRef =schemaID;
//multimediaComponent.Metadata = "";
StreamUpload2010Client streamClient = new StreamUpload2010Client();
FileStream objfilestream = new FileStream(#"\My Documents\images.jpg",
FileMode.Open, FileAccess.Read);
string tempLocation = streamClient.UploadBinaryContent("images.jpg",
objfilestream);
BinaryContentData binaryContent = new BinaryContentData();
binaryContent.UploadFromFile = tempLocation;
binaryContent.Filename = "images.jpg";
binaryContent.MultimediaType = new LinkToMultimediaTypeData()
{
// for jpg file
IdRef = "tcm:0-2-65544"
};
multimediaComponent.BinaryContent = binaryContent;
IdentifiableObjectData savedComponent = client.Save(multimediaComponent,
new ReadOptions());
client.CheckIn(savedComponent.Id, null);
streamClient.Close();
client.Close();
Console.WriteLine(savedComponent.Id);
//}
}
I don't know why your code not working but following code is working for me
public static ComponentData GenerateMultiMediaComponent(TridionGeneration tridionGeneration, XmlData newsArticle, string componentName)
{
try
{
Dictionary<string, object> dicTridion = Common.GetTridionObject(tridionGeneration.client, ItemType.Component, tridionGeneration.Settings.ComponentFolderUri, componentName);
int objectCount = (int)dicTridion["count"];
SchemaFieldsData schemaFields = tridionGeneration.client.ReadSchemaFields(tridionGeneration.Settings.SchemaUri, true, new ReadOptions());
ComponentData componentData = (ComponentData)tridionGeneration.client.GetDefaultData(ItemType.Component, tridionGeneration.Settings.ComponentFolderUri);
if (schemaFields.Fields != null)
{
var fields = Fields.ForContentOf(schemaFields);
Helper.FillSchemaFields(tridionGeneration, fields);
componentData.Content = fields.ToString();
}
if (schemaFields.MetadataFields != null)
{
var metafields = Fields.ForMetadataOf(schemaFields, componentData);
Helper.FillSchemaFields(tridionGeneration, metafields);
componentData.Metadata = metafields.ToString();
}
componentData.Title = (objectCount == 0) ? componentName : componentName + " " + (objectCount + 1).ToString();
componentData.ComponentType = ComponentType.Multimedia;
StreamUpload2010Client streamClient = new StreamUpload2010Client();
FileStream objfilestream = new FileStream(#"[IMAGE_PATH]", FileMode.Open, FileAccess.Read);
string tempLocation = streamClient.UploadBinaryContent("images.jpg", objfilestream);
BinaryContentData binaryContent = new BinaryContentData();
binaryContent.UploadFromFile = tempLocation;
binaryContent.Filename = "[IMAGE_NAME]";
componentData.BinaryContent = binaryContent;
binaryContent.MultimediaType = new LinkToMultimediaTypeData()
{
IdRef = "tcm:0-2-65544"
};
componentData = (ComponentData)tridionGeneration.client.Create(componentData, new ReadOptions());
return componentData;
}
catch (Exception ex)
{
return null;
}
}
Here is the Helper class:
public static class Helper
{
public static void FillSchemaFields(TridionGeneration tridionGeneration, Fields fields)
{
List<XmlData> data = XmlHelper.xmlData;
var ofield = fields.GetEnumerator();
while (ofield.MoveNext())
{
Field f = ofield.Current;
FillFieldValue(tridionGeneration, fields, f, data[0]);
}
}
private static void FillFieldValue(TridionGeneration tridionGeneration, Fields fields, Field f, XmlData data)
{
if (f.Type == typeof(MultimediaLinkFieldDefinitionData))
{
fields[f.Name].Value = tridionGeneration.Settings.DefaultImageUri;
}
else if (f.Type != typeof(EmbeddedSchemaFieldDefinitionData))
{
foreach (XmlData fieldvalue in data.Attributes)
{
if (f.Type == typeof(DateFieldDefinitionData))
{
if (fieldvalue.text.ToLower() == f.Name.ToLower())
{
fields[f.Name].Value = Convert.ToDateTime(fieldvalue.value).ToString("yyyy-MM-ddTHH:mm:ss");
}
else
{
string val = FindSchemaValue(tridionGeneration, fieldvalue.Attributes, f.Name);
if (!string.IsNullOrEmpty(val))
{
fields[f.Name].Value = Convert.ToDateTime(val).ToString("yyyy-MM-ddTHH:mm:ss");
}
}
}
else
{
if (fieldvalue.text.ToLower() == f.Name.ToLower())
{
fields[f.Name].Value = System.Net.WebUtility.HtmlEncode(fieldvalue.value);
}
else
{
string val = FindSchemaValue(tridionGeneration, fieldvalue.Attributes, f.Name);
if (!string.IsNullOrEmpty(val))
{
fields[f.Name].Value = System.Net.WebUtility.HtmlEncode(val);
}
}
}
}
}
else
{
Fields fs = f.GetSubFields();
var ofield = fs.GetEnumerator();
while (ofield.MoveNext())
{
Field ff = ofield.Current;
FillFieldValue(tridionGeneration, fs, ff, data);
}
}
}
private static string FindSchemaValue(TridionGeneration tridionGeneration, List<XmlData> data, string fieldname)
{
foreach (XmlData fieldvalue in data)
{
if (fieldvalue.text.ToLower() == fieldname.ToLower())
{
return fieldvalue.value;
}
else
{
FindSchemaValue(tridionGeneration, fieldvalue.Attributes, fieldname);
}
}
return "";
}
}
and the Fields class:
public class Fields
{
private ItemFieldDefinitionData[] definitions;
private XmlNamespaceManager namespaceManager;
private XmlElement root; // the root element under which these fields live
// at any point EITHER data OR parent has a value
private SchemaFieldsData data; // the schema fields data as retrieved from the core service
private Fields parent; // the parent fields (so we're an embedded schema), where we can find the data
public Fields(SchemaFieldsData _data, ItemFieldDefinitionData[] _definitions, string _content = null, string _rootElementName = null)
{
data = _data;
definitions = _definitions;
var content = new XmlDocument();
if (!string.IsNullOrEmpty(_content))
{
content.LoadXml(_content);
}
else
{
content.AppendChild(content.CreateElement(string.IsNullOrEmpty(_rootElementName) ? _data.RootElementName : _rootElementName, _data.NamespaceUri));
}
root = content.DocumentElement;
namespaceManager = new XmlNamespaceManager(content.NameTable);
namespaceManager.AddNamespace("custom", _data.NamespaceUri);
}
public Fields(Fields _parent, ItemFieldDefinitionData[] _definitions, XmlElement _root)
{
definitions = _definitions;
parent = _parent;
root = _root;
}
public static Fields ForContentOf(SchemaFieldsData _data)
{
return new Fields(_data, _data.Fields);
}
public static Fields ForContentOf(SchemaFieldsData _data, ComponentData _component)
{
return new Fields(_data, _data.Fields, _component.Content);
}
public static Fields ForMetadataOf(SchemaFieldsData _data, RepositoryLocalObjectData _item)
{
return new Fields(_data, _data.MetadataFields, _item.Metadata, "Metadata");
}
public string NamespaceUri
{
get { return data != null ? data.NamespaceUri : parent.NamespaceUri; }
}
public XmlNamespaceManager NamespaceManager
{
get { return parent != null ? parent.namespaceManager : namespaceManager; }
}
internal IEnumerable<XmlElement> GetFieldElements(ItemFieldDefinitionData definition)
{
return root.SelectNodes("custom:" + definition.Name, NamespaceManager).OfType<XmlElement>();
}
internal XmlElement AddFieldElement(ItemFieldDefinitionData definition)
{
var newElement = root.OwnerDocument.CreateElement(definition.Name, NamespaceUri);
XmlNodeList nodes = root.SelectNodes("custom:" + definition.Name, NamespaceManager);
XmlElement referenceElement = null;
if (nodes.Count > 0)
{
referenceElement = (XmlElement)nodes[nodes.Count - 1];
}
else
{
// this is the first value for this field, find its position in the XML based on the field order in the schema
bool foundUs = false;
for (int i = definitions.Length - 1; i >= 0; i--)
{
if (!foundUs)
{
if (definitions[i].Name == definition.Name)
{
foundUs = true;
}
}
else
{
var values = GetFieldElements(definitions[i]);
if (values.Count() > 0)
{
referenceElement = values.Last();
break; // from for loop
}
}
} // for every definition in reverse order
} // no existing values found
root.InsertAfter(newElement, referenceElement); // if referenceElement is null, will insert as first child
return newElement;
}
public IEnumerator<Field> GetEnumerator()
{
return (IEnumerator<Field>)new FieldEnumerator(this, definitions);
}
public Field this[string _name]
{
get
{
var definition = definitions.First<ItemFieldDefinitionData>(ifdd => ifdd.Name == _name);
if (definition == null) throw new ArgumentOutOfRangeException("Unknown field '" + _name + "'");
return new Field(this, definition);
}
}
public override string ToString()
{
return root.OuterXml;
}
}
public class FieldEnumerator : IEnumerator<Field>
{
private Fields fields;
private ItemFieldDefinitionData[] definitions;
// Enumerators are positioned before the first element until the first MoveNext() call
int position = -1;
public FieldEnumerator(Fields _fields, ItemFieldDefinitionData[] _definitions)
{
fields = _fields;
definitions = _definitions;
}
public bool MoveNext()
{
position++;
return (position < definitions.Length);
}
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public Field Current
{
get
{
try
{
return new Field(fields, definitions[position]);
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public void Dispose()
{
}
}
public class Field
{
private Fields fields;
private ItemFieldDefinitionData definition;
public Field(Fields _fields, ItemFieldDefinitionData _definition)
{
fields = _fields;
definition = _definition;
}
public string Name
{
get { return definition.Name; }
}
public Type Type
{
get { return definition.GetType(); }
}
public string Value
{
get
{
return Values.Count > 0 ? Values[0] : null;
}
set
{
if (Values.Count == 0) fields.AddFieldElement(definition);
Values[0] = value;
}
}
public ValueCollection Values
{
get
{
return new ValueCollection(fields, definition);
}
}
public void AddValue(string value = null)
{
XmlElement newElement = fields.AddFieldElement(definition);
if (value != null) newElement.InnerText = value;
}
public void RemoveValue(string value)
{
var elements = fields.GetFieldElements(definition);
foreach (var element in elements)
{
if (element.InnerText == value)
{
element.ParentNode.RemoveChild(element);
}
}
}
public void RemoveValue(int i)
{
var elements = fields.GetFieldElements(definition).ToArray();
elements[i].ParentNode.RemoveChild(elements[i]);
}
public IEnumerable<Fields> SubFields
{
get
{
var embeddedFieldDefinition = definition as EmbeddedSchemaFieldDefinitionData;
if (embeddedFieldDefinition != null)
{
var elements = fields.GetFieldElements(definition);
foreach (var element in elements)
{
yield return new Fields(fields, embeddedFieldDefinition.EmbeddedFields, (XmlElement)element);
}
}
}
}
public Fields GetSubFields(int i = 0)
{
var embeddedFieldDefinition = definition as EmbeddedSchemaFieldDefinitionData;
if (embeddedFieldDefinition != null)
{
var elements = fields.GetFieldElements(definition);
if (i == 0 && !elements.Any())
{
// you can always set the first value of any field without calling AddValue, so same applies to embedded fields
AddValue();
elements = fields.GetFieldElements(definition);
}
return new Fields(fields, embeddedFieldDefinition.EmbeddedFields, elements.ToArray()[i]);
}
else
{
throw new InvalidOperationException("You can only GetSubField on an EmbeddedSchemaField");
}
}
// The subfield with the given name of this field
public Field this[string name]
{
get { return GetSubFields()[name]; }
}
// The subfields of the given value of this field
public Fields this[int i]
{
get { return GetSubFields(i); }
}
}
Can you try this?
multimediaComponent.Metadata = "<Metadata/>";

Resources