We are trying to upload an image using SDL Tridions SOAP API using Apache's Java CXF. And we are stuck during the creation of a component data component with binary content with this error message:
com.sdltridion.contentmanager.coreservice._2013.ICoreServiceSaveCoreServiceFaultFaultFaultMessage:
Invalid value for property 'Filename'. Property Filename value is unknown.
As we can tell from the code below, the Filename property is actually set and also available in the SOAP request. What can be the reason for this error message?
This is the actual SOAP request being sent to Tridion:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Save xmlns="http://www.sdltridion.com/ContentManager/CoreService/2013" xmlns:ns2="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:ns3="http://www.sdltridion.com/ContentManager/R6" xmlns:ns4="http://www.sdltridion.com/Security" xmlns:ns5="http://schemas.microsoft.com/2003/10/Serialization/">
<deltaData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns3:ComponentData">
<ns3:BluePrintInfo>
<ns3:IsLocalized>false</ns3:IsLocalized>
<ns3:IsShared>false</ns3:IsShared>
<ns3:LinkToRepositoryData>
<ns3:IdRef>tcm:0-5-1</ns3:IdRef>
<ns3:Title>200 Master Content (ENG)</ns3:Title>
</ns3:LinkToRepositoryData>
</ns3:BluePrintInfo>
<ns3:IsPublishedInContext>false</ns3:IsPublishedInContext>
<ns3:LocationInfo>
<ns3:RepositoryData xsi:type="ns3:LinkToRepositoryData">
<ns3:IdRef>tcm:0-5-1</ns3:IdRef>
<ns3:Title>200 Master Content (ENG)</ns3:Title>
</ns3:RepositoryData>
<ns3:OrganizationalItem>
<ns3:IdRef>tcm:5-3584-2</ns3:IdRef>
<ns3:Title>Archive</ns3:Title>
</ns3:OrganizationalItem>
<ns3:Path>\200 Master Content (ENG)\Building Blocks\Test\Multimedia\Images\Archive</ns3:Path>
<ns3:WebDavUrl>/webdav/200%20Master%20Content%20(ENG)/Building%20Blocks/Test/Multimedia/Images/Archive/</ns3:WebDavUrl>
</ns3:LocationInfo>
<ns3:Metadata/>
<ns3:ApprovalStatus>
<ns3:IdRef>tcm:0-0-0</ns3:IdRef>
<ns3:Title>Undefined</ns3:Title>
</ns3:ApprovalStatus>
<ns3:BinaryContentData>
<ns3:FileSize>5425</ns3:FileSize>
<ns3:Filename>Hydrangeas.jpg</ns3:Filename>
<ns3:IsExternal>false</ns3:IsExternal>
<ns3:LinkToMultimediaTypeData>
<ns3:IdRef>tcm:0-2-65544</ns3:IdRef>
<ns3:Title>Jpeg image</ns3:Title>
</ns3:LinkToMultimediaTypeData>
<ns3:UploadFromFile>C:\Windows\TEMP\tmp1AB8.jpg</ns3:UploadFromFile>
<ns3:MimeType>image/jpeg</ns3:MimeType>
</ns3:BinaryContentData>
<ns3:ComponentType>Multimedia</ns3:ComponentType>
<ns3:IsBasedOnMandatorySchema>false</ns3:IsBasedOnMandatorySchema>
<ns3:IsBasedOnTridionWebSchema>true</ns3:IsBasedOnTridionWebSchema>
<ns3:Schema>
<ns3:IdRef>tcm:5-153-8</ns3:IdRef>
<ns3:Title>Default Multimedia Schema</ns3:Title>
</ns3:Schema>
</deltaData>
<readBackOptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns3:SynchronizeOptions"/>
</Save>
Any idea about what this error message might actually mean ('Property Filename value is unknown')?
Below is the actual SOAP response coming from Tridion:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://www.sdltridion.com/ContentManager/CoreService/2013">a:InvalidPropertyValueException</faultcode>
<faultstring xml:lang="en-US">Invalid value for property 'Filename'. Property Filename value is unknown.</faultstring>
<detail>
<CoreServiceFault xmlns="http://www.sdltridion.com/ContentManager/R6" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Category>Validation</Category>
<ErrorCode>ElementNotFound</ErrorCode>
<ExceptionName>InvalidPropertyValueException</ExceptionName>
<Messages>
<Message>Invalid value for property 'Filename'. Property Filename value is unknown.</Message>
</Messages>
</CoreServiceFault>
</detail>
</s:Fault>
This is the error I see in the Tridion Event viewer:
Invalid value for property 'Filename'. Property Filename value is unknown.
Component: Tridion.ContentManager.CoreService
Errorcode: 777
User: NT AUTHORITY\NETWORK SERVICE
StackTrace Information Details:
at Tridion.ContentManager.ContentManagement.BinaryContent.AssertValidProperties(IEnumerable`1 allowedMultiMediaTypes, Boolean changedToInternalBinaryContent)
at Tridion.ContentManager.ContentManagement.Component.OnSaving(SaveEventArgs eventArgs)
at Tridion.ContentManager.IdentifiableObject.Save(SaveEventArgs eventArgs)
at Tridion.ContentManager.ContentManagement.VersionedItem.Save(Boolean checkInAfterSave)
at Tridion.ContentManager.ContentManagement.VersionedItem.Save()
at Tridion.ContentManager.CoreService.CoreServiceBase.Save(IdentifiableObjectData deltaData, ReadOptions readBackOptions)
at SyncInvokeSave(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at Tridion.ContentManager.CoreService.CoreServiceInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Project Setup
We have generated the Java client files using the WSDL using CXF's codegin plugin:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>http://${cms.system}/webservices/CoreService2013.svc?wsdl</wsdl>
<wsdlLocation>http://${cms.system}/webservices/CoreService2013.svc?wsdl</wsdlLocation>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
This works fine. Then we instantiated the implementation of the ICoreService using this code:
private ICoreService createICoreService(String address, String username, String password) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
addInterceptors(factory);
factory.setServiceClass(ICoreService.class);
factory.setAddress(address);
ICoreService iCoreService = (ICoreService) factory.create();
activateAuthentication(username, password);
return iCoreService;
}
...
private void authenticateNtlm(final String username, final String password) {
class MyAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
}
Authenticator.setDefault(new MyAuthenticator());
}
We also instantiate the CoreService2013 class like so:
@Bean(name = "coreService2013")
public CoreService2013 getService() {
try {
return new CoreService2013(new URL(coreServiceAddress));
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
}
This setup seems to work, since we manage to retrieve information from Tridion and are also able to write ComponentData to Tridion.
Here is an example of a test which runs fine with our setup:
public class ICoreServicesConfigTest {
private ICoreService iCoreService;
@Before
public void setUp() throws Exception {
AnnotationConfigApplicationContext beanFactory = new AnnotationConfigApplicationContext(ICoreServicesConfig.class);
iCoreService = (ICoreService) beanFactory.getBean("iCoreService");
}
@Test
public void whenUseICoreService_ShouldRetrieveApplicationIds() throws ICoreServiceGetApplicationIdsCoreServiceFaultFaultFaultMessage {
ArrayOfstring res = iCoreService.getApplicationIds();
List<String> strings = res.getString();
assertThat(strings, is(not(nullValue())));
assertThat(strings.isEmpty(), is(false));
for (String id : strings) {
System.out.println(id);
}
}
}
Now this is what we did not manage to get working yet: we are trying to upload an image and then create a ComponentData with binary content. As we have understood we need to:
- upload the data
- create the component data with the binary content.
The first item seems to be working even though we are facing challenges with the 16KB limit mentioned in this blog
Here is the code for uploading the data:
private File uploadFile(File file) throws IOException, IStreamUploadUploadBinaryByteArrayCoreServiceFaultFaultFaultMessage {
byte[] fileData = new byte[(int) file.length()];
CoreService2013 coreService2013 = new CoreService2013();
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(fileData);
dis.close();
IStreamUpload clientUpload = coreService2013.getStreamUploadBasicHttp();
String uploadFile = clientUpload.uploadBinaryByteArray(file.getName(), fileData);
return new File(uploadFile);
}
And this is the code for the ComponentData creation:
@Test
public void whenUseICoreService_ShouldCreateTridionImageComponent() throws ICoreServiceGetApplicationIdsCoreServiceFaultFaultFaultMessage,
ICoreServiceReadCoreServiceFaultFaultFaultMessage, ICoreServiceSaveCoreServiceFaultFaultFaultMessage, ICoreServiceCheckInCoreServiceFaultFaultFaultMessage,
ClassNotFoundException, IOException, IStreamUploadUploadBinaryByteArrayCoreServiceFaultFaultFaultMessage {
ComponentData data = new ComponentData();
ObjectFactory objectFactory = new ObjectFactory();
setSchema(data, objectFactory, "tcm:5-153-8", "Default Multimedia Schema");
createApprovalStatusData(data, objectFactory);
JAXBElement<BinaryContentData> binaryContentData = objectFactory.createBinaryContentData(getBinaryContentData(objectFactory));
data.setBinaryContent(binaryContentData);
data.setComponentType(objectFactory.createComponentType(ComponentType.MULTIMEDIA));
data.setIsBasedOnMandatorySchema(objectFactory.createComponentDataIsBasedOnMandatorySchema(false));
data.setIsBasedOnTridionWebSchema(objectFactory.createComponentDataIsBasedOnTridionWebSchema(true));
data.setIsPublishedInContext(objectFactory.createRepositoryLocalObjectDataIsPublishedInContext(false));
setBluePrintInfo(data, objectFactory);
setLocationInfo(data, objectFactory, "\\200 Master Content (ENG)\\Building Blocks\\Test\\Multimedia\\Images\\Archive",
"/webdav/200%20Master%20Content%20(ENG)/Building%20Blocks/Test/Multimedia/Images/Archive/");
data.setMetadata(objectFactory.createRepositoryLocalObjectDataMetadata(""));
IdentifiableObjectData res = iCoreService.save(data, objectFactory.createReadOptions());
assertThat(res, is(not(nullValue())));
}
private BinaryContentData getBinaryContentData(ObjectFactory objectFactory) throws IOException, IStreamUploadUploadBinaryByteArrayCoreServiceFaultFaultFaultMessage {
BinaryContentData binaryContentData = objectFactory.createBinaryContentData();
File localFile = LOCAL_FILE;
File remoteFile = uploadFile(localFile);
binaryContentData.setFilename(objectFactory.createBinaryDataFilename(LOCAL_FILE.getName()));
binaryContentData.setFileSize(objectFactory.createBinaryContentDataFileSize((int) LOCAL_FILE.length()));
binaryContentData.setUploadFromFile(objectFactory.createBinaryContentDataUploadFromFile(remoteFile.getAbsolutePath()));
LinkToMultimediaTypeData linkToMultimediaTypeData = objectFactory.createLinkToMultimediaTypeData();
linkToMultimediaTypeData.setIdRef(objectFactory.createLinkIdRef("tcm:0-2-65544"));
linkToMultimediaTypeData.setTitle(objectFactory.createLinkTitle("Jpeg image"));
binaryContentData.setMultimediaType(objectFactory.createLinkToMultimediaTypeData(linkToMultimediaTypeData));
binaryContentData.setMimeType(objectFactory.createBinaryContentDataMimeType("image/jpeg"));
return binaryContentData;
}
uploadFile(file)
call work now or not? If that one doesn't work, then all the additional code is obfuscating the question I would say (so it would make sense to edit the question and remove it).