001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.lar;
016    
017    import com.liferay.portal.kernel.lar.ExportImportClassedModelUtil;
018    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
019    import com.liferay.portal.kernel.lar.PortletDataContext;
020    import com.liferay.portal.kernel.lar.PortletDataContextFactoryUtil;
021    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
022    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
023    import com.liferay.portal.kernel.lar.UserIdStrategy;
024    import com.liferay.portal.kernel.util.ListUtil;
025    import com.liferay.portal.kernel.util.Time;
026    import com.liferay.portal.kernel.workflow.WorkflowConstants;
027    import com.liferay.portal.kernel.xml.Document;
028    import com.liferay.portal.kernel.xml.Element;
029    import com.liferay.portal.kernel.xml.SAXReaderUtil;
030    import com.liferay.portal.kernel.zip.ZipReader;
031    import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
032    import com.liferay.portal.kernel.zip.ZipWriter;
033    import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
034    import com.liferay.portal.model.Company;
035    import com.liferay.portal.model.Group;
036    import com.liferay.portal.model.StagedModel;
037    import com.liferay.portal.service.CompanyLocalServiceUtil;
038    import com.liferay.portal.service.GroupLocalServiceUtil;
039    import com.liferay.portal.service.ServiceContext;
040    import com.liferay.portal.service.ServiceContextThreadLocal;
041    import com.liferay.portal.test.DeleteAfterTestRun;
042    import com.liferay.portal.util.test.GroupTestUtil;
043    import com.liferay.portal.util.test.ServiceContextTestUtil;
044    import com.liferay.portal.util.test.TestPropsValues;
045    import com.liferay.portlet.asset.model.AssetCategory;
046    import com.liferay.portlet.asset.model.AssetEntry;
047    import com.liferay.portlet.asset.model.AssetTag;
048    import com.liferay.portlet.asset.model.AssetVocabulary;
049    import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
050    import com.liferay.portlet.asset.service.AssetEntryLocalServiceUtil;
051    import com.liferay.portlet.asset.service.AssetTagLocalServiceUtil;
052    import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
053    import com.liferay.portlet.asset.util.test.AssetTestUtil;
054    import com.liferay.portlet.messageboards.model.MBMessage;
055    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
056    import com.liferay.portlet.messageboards.util.test.MBTestUtil;
057    import com.liferay.portlet.ratings.model.RatingsEntry;
058    import com.liferay.portlet.ratings.service.RatingsEntryLocalServiceUtil;
059    import com.liferay.portlet.ratings.util.test.RatingsTestUtil;
060    
061    import java.io.Serializable;
062    
063    import java.util.ArrayList;
064    import java.util.Date;
065    import java.util.HashMap;
066    import java.util.Iterator;
067    import java.util.LinkedHashMap;
068    import java.util.List;
069    import java.util.Map;
070    
071    import org.junit.After;
072    import org.junit.Assert;
073    import org.junit.Before;
074    import org.junit.Test;
075    
076    /**
077     * @author Daniel Kocsis
078     * @author Mate Thurzo
079     */
080    public abstract class BaseStagedModelDataHandlerTestCase {
081    
082            @Before
083            public void setUp() throws Exception {
084                    liveGroup = GroupTestUtil.addGroup();
085                    stagingGroup = GroupTestUtil.addGroup();
086    
087                    ServiceContext serviceContext =
088                            ServiceContextTestUtil.getServiceContext(stagingGroup.getGroupId());
089    
090                    ServiceContextThreadLocal.pushServiceContext(serviceContext);
091            }
092    
093            @After
094            public void tearDown() throws Exception {
095                    ServiceContextThreadLocal.popServiceContext();
096            }
097    
098            @Test
099            public void testStagedModelDataHandler() throws Exception {
100    
101                    // Export
102    
103                    initExport();
104    
105                    Map<String, List<StagedModel>> dependentStagedModelsMap =
106                            addDependentStagedModelsMap(stagingGroup);
107    
108                    StagedModel stagedModel = addStagedModel(
109                            stagingGroup, dependentStagedModelsMap);
110    
111                    // Assets
112    
113                    StagedModelAssets stagedModelAssets = updateAssetEntry(
114                            stagedModel, stagingGroup);
115    
116                    // Comments
117    
118                    addComments(stagedModel);
119    
120                    // Ratings
121    
122                    addRatings(stagedModel);
123    
124                    StagedModelDataHandlerUtil.exportStagedModel(
125                            portletDataContext, stagedModel);
126    
127                    validateExport(
128                            portletDataContext, stagedModel, dependentStagedModelsMap);
129    
130                    // Import
131    
132                    initImport();
133    
134                    deleteStagedModel(stagedModel, dependentStagedModelsMap, stagingGroup);
135    
136                    // Reread the staged model for import from ZIP for true testing
137    
138                    StagedModel exportedStagedModel = readExportedStagedModel(stagedModel);
139    
140                    Assert.assertNotNull(exportedStagedModel);
141    
142                    StagedModelDataHandlerUtil.importStagedModel(
143                            portletDataContext, exportedStagedModel);
144    
145                    validateImport(
146                            stagedModel, stagedModelAssets, dependentStagedModelsMap,
147                            liveGroup);
148            }
149    
150            protected void addComments(StagedModel stagedModel) throws Exception {
151                    if (!isCommentableStagedModel()) {
152                            return;
153                    }
154    
155                    MBTestUtil.addDiscussionMessage(
156                            stagingGroup.getGroupId(),
157                            ExportImportClassedModelUtil.getClassName(stagedModel),
158                            ExportImportClassedModelUtil.getClassPK(stagedModel));
159            }
160    
161            protected List<StagedModel> addDependentStagedModel(
162                    Map<String, List<StagedModel>> dependentStagedModelsMap, Class<?> clazz,
163                    StagedModel dependentStagedModel) {
164    
165                    List<StagedModel> dependentStagedModels = dependentStagedModelsMap.get(
166                            clazz.getSimpleName());
167    
168                    if (dependentStagedModels == null) {
169                            dependentStagedModels = new ArrayList<StagedModel>();
170    
171                            dependentStagedModelsMap.put(
172                                    clazz.getSimpleName(), dependentStagedModels);
173                    }
174    
175                    dependentStagedModels.add(dependentStagedModel);
176    
177                    return dependentStagedModels;
178            }
179    
180            protected Map<String, List<StagedModel>> addDependentStagedModelsMap(
181                            Group group)
182                    throws Exception {
183    
184                    return new HashMap<String, List<StagedModel>>();
185            }
186    
187            protected void addRatings(StagedModel stagedModel) throws Exception {
188                    RatingsTestUtil.addEntry(
189                            ExportImportClassedModelUtil.getClassName(stagedModel),
190                            ExportImportClassedModelUtil.getClassPK(stagedModel));
191            }
192    
193            protected abstract StagedModel addStagedModel(
194                            Group group,
195                            Map<String, List<StagedModel>> dependentStagedModelsMap)
196                    throws Exception;
197    
198            protected void deleteStagedModel(
199                            StagedModel stagedModel,
200                            Map<String, List<StagedModel>> dependentStagedModelsMap,
201                            Group group)
202                    throws Exception {
203            }
204    
205            protected AssetEntry fetchAssetEntry(StagedModel stagedModel, Group group)
206                    throws Exception {
207    
208                    return AssetEntryLocalServiceUtil.fetchEntry(
209                            group.getGroupId(), stagedModel.getUuid());
210            }
211    
212            protected Date getEndDate() {
213                    return new Date();
214            }
215    
216            protected Map<String, String[]> getParameterMap() {
217                    Map<String, String[]> parameterMap =
218                            new LinkedHashMap<String, String[]>();
219    
220                    parameterMap.put(
221                            PortletDataHandlerKeys.DATA_STRATEGY,
222                            new String[] {
223                                    PortletDataHandlerKeys.DATA_STRATEGY_MIRROR_OVERWRITE});
224                    parameterMap.put(
225                            PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
226                            new String[] {Boolean.TRUE.toString()});
227                    parameterMap.put(
228                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
229                            new String[] {Boolean.TRUE.toString()});
230                    parameterMap.put(
231                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
232                            new String[] {Boolean.TRUE.toString()});
233                    parameterMap.put(
234                            PortletDataHandlerKeys.PORTLET_DATA,
235                            new String[] {Boolean.TRUE.toString()});
236                    parameterMap.put(
237                            PortletDataHandlerKeys.PORTLET_DATA_ALL,
238                            new String[] {Boolean.TRUE.toString()});
239                    parameterMap.put(
240                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
241                            new String[] {Boolean.TRUE.toString()});
242    
243                    return parameterMap;
244            }
245    
246            protected abstract StagedModel getStagedModel(String uuid, Group group);
247    
248            protected abstract Class<? extends StagedModel> getStagedModelClass();
249    
250            protected Date getStartDate() {
251                    return new Date(System.currentTimeMillis() - Time.HOUR);
252            }
253    
254            protected void initExport() throws Exception {
255                    zipWriter = ZipWriterFactoryUtil.getZipWriter();
256    
257                    portletDataContext =
258                            PortletDataContextFactoryUtil.createExportPortletDataContext(
259                                    stagingGroup.getCompanyId(), stagingGroup.getGroupId(),
260                                    getParameterMap(), getStartDate(), getEndDate(), zipWriter);
261    
262                    rootElement = SAXReaderUtil.createElement("root");
263    
264                    portletDataContext.setExportDataRootElement(rootElement);
265    
266                    missingReferencesElement = SAXReaderUtil.createElement(
267                            "missing-references");
268    
269                    portletDataContext.setMissingReferencesElement(
270                            missingReferencesElement);
271            }
272    
273            protected void initImport() throws Exception {
274                    PortletExporter portletExporter = PortletExporter.getInstance();
275    
276                    portletExporter.exportAssetTags(portletDataContext);
277    
278                    userIdStrategy = new CurrentUserIdStrategy(TestPropsValues.getUser());
279                    zipReader = ZipReaderFactoryUtil.getZipReader(zipWriter.getFile());
280    
281                    String xml = zipReader.getEntryAsString("/manifest.xml");
282    
283                    if (xml == null) {
284                            Document document = SAXReaderUtil.createDocument();
285    
286                            Element rootElement = document.addElement("root");
287    
288                            rootElement.addElement("header");
289    
290                            zipWriter.addEntry("/manifest.xml", document.asXML());
291    
292                            zipReader = ZipReaderFactoryUtil.getZipReader(zipWriter.getFile());
293                    }
294    
295                    portletDataContext =
296                            PortletDataContextFactoryUtil.createImportPortletDataContext(
297                                    liveGroup.getCompanyId(), liveGroup.getGroupId(),
298                                    getParameterMap(), userIdStrategy, zipReader);
299    
300                    portletDataContext.setImportDataRootElement(rootElement);
301    
302                    Group sourceCompanyGroup = GroupLocalServiceUtil.getCompanyGroup(
303                            stagingGroup.getCompanyId());
304    
305                    portletDataContext.setSourceCompanyGroupId(
306                            sourceCompanyGroup.getGroupId());
307    
308                    portletDataContext.setSourceCompanyId(stagingGroup.getCompanyId());
309                    portletDataContext.setSourceGroupId(stagingGroup.getGroupId());
310    
311                    PortletImporter portletImporter = PortletImporter.getInstance();
312    
313                    portletImporter.readAssetTags(portletDataContext);
314            }
315    
316            protected boolean isCommentableStagedModel() {
317                    return false;
318            }
319    
320            protected StagedModel readExportedStagedModel(StagedModel stagedModel) {
321                    String stagedModelPath = ExportImportPathUtil.getModelPath(stagedModel);
322    
323                    StagedModel exportedStagedModel =
324                            (StagedModel)portletDataContext.getZipEntryAsObject(
325                                    stagedModelPath);
326    
327                    return exportedStagedModel;
328            }
329    
330            protected StagedModelAssets updateAssetEntry(
331                            StagedModel stagedModel, Group group)
332                    throws Exception {
333    
334                    AssetEntry assetEntry = fetchAssetEntry(stagedModel, group);
335    
336                    if (assetEntry == null) {
337                            return null;
338                    }
339    
340                    AssetVocabulary assetVocabulary = AssetTestUtil.addVocabulary(
341                            stagingGroup.getGroupId());
342    
343                    AssetCategory assetCategory = AssetTestUtil.addCategory(
344                            stagingGroup.getGroupId(), assetVocabulary.getVocabularyId());
345    
346                    Company company = CompanyLocalServiceUtil.getCompany(
347                            stagedModel.getCompanyId());
348    
349                    Group companyGroup = company.getGroup();
350    
351                    AssetVocabulary companyAssetVocabulary = AssetTestUtil.addVocabulary(
352                            companyGroup.getGroupId());
353    
354                    AssetCategory companyAssetCategory = AssetTestUtil.addCategory(
355                            companyGroup.getGroupId(),
356                            companyAssetVocabulary.getVocabularyId());
357    
358                    AssetTag assetTag = AssetTestUtil.addTag(stagingGroup.getGroupId());
359    
360                    AssetEntryLocalServiceUtil.updateEntry(
361                            TestPropsValues.getUserId(), stagingGroup.getGroupId(),
362                            assetEntry.getClassName(), assetEntry.getClassPK(),
363                            new long[] {
364                                    assetCategory.getCategoryId(),
365                                    companyAssetCategory.getCategoryId()
366                            },
367                            new String[] {assetTag.getName()});
368    
369                    return new StagedModelAssets(assetCategory, assetTag, assetVocabulary);
370            }
371    
372            protected void validateAssets(
373                            StagedModel stagedModel, StagedModelAssets stagedModelAssets,
374                            Group group)
375                    throws Exception {
376    
377                    if (stagedModelAssets == null) {
378                            return;
379                    }
380    
381                    AssetEntry assetEntry = fetchAssetEntry(stagedModel, group);
382    
383                    List<AssetCategory> assetCategories =
384                            AssetCategoryLocalServiceUtil.getEntryCategories(
385                                    assetEntry.getEntryId());
386    
387                    Assert.assertEquals(2, assetCategories.size());
388    
389                    AssetCategory stagedAssetCategory =
390                            stagedModelAssets.getAssetCategory();
391    
392                    AssetCategory importedAssetCategory = null;
393    
394                    Company company = CompanyLocalServiceUtil.getCompany(
395                            group.getCompanyId());
396    
397                    long companyGroupId = company.getGroupId();
398    
399                    for (AssetCategory assetCategory : assetCategories) {
400                            long groupId = assetCategory.getGroupId();
401    
402                            if (groupId != companyGroupId) {
403                                    importedAssetCategory = assetCategory;
404    
405                                    break;
406                            }
407                    }
408    
409                    Assert.assertEquals(
410                            stagedAssetCategory.getUuid(), importedAssetCategory.getUuid());
411    
412                    List<AssetTag> assetTags = AssetTagLocalServiceUtil.getEntryTags(
413                            assetEntry.getEntryId());
414    
415                    Assert.assertEquals(1, assetTags.size());
416    
417                    AssetTag assetTag = stagedModelAssets.getAssetTag();
418                    AssetTag importedAssetTag = assetTags.get(0);
419    
420                    Assert.assertEquals(assetTag.getName(), importedAssetTag.getName());
421    
422                    AssetVocabulary assetVocabulary =
423                            stagedModelAssets.getAssetVocabulary();
424                    AssetVocabulary importedAssetVocabulary =
425                            AssetVocabularyLocalServiceUtil.getVocabulary(
426                                    importedAssetCategory.getVocabularyId());
427    
428                    Assert.assertEquals(
429                            assetVocabulary.getUuid(), importedAssetVocabulary.getUuid());
430            }
431    
432            protected void validateComments(
433                            StagedModel stagedModel, StagedModel importedStagedModel,
434                            Group group)
435                    throws Exception {
436    
437                    if (!isCommentableStagedModel()) {
438                            return;
439                    }
440    
441                    List<MBMessage> discussionMBMessages =
442                            MBMessageLocalServiceUtil.getMessages(
443                                    ExportImportClassedModelUtil.getClassName(stagedModel),
444                                    ExportImportClassedModelUtil.getClassPK(stagedModel),
445                                    WorkflowConstants.STATUS_ANY);
446    
447                    if (ListUtil.isEmpty(discussionMBMessages)) {
448                            return;
449                    }
450    
451                    int importedDiscussionMBMessagesCount =
452                            MBMessageLocalServiceUtil.getDiscussionMessagesCount(
453                                    ExportImportClassedModelUtil.getClassName(importedStagedModel),
454                                    ExportImportClassedModelUtil.getClassPK(importedStagedModel),
455                                    WorkflowConstants.STATUS_ANY);
456    
457                    Assert.assertEquals(
458                            discussionMBMessages.size(), importedDiscussionMBMessagesCount + 1);
459    
460                    for (MBMessage discussionMBMessage : discussionMBMessages) {
461                            if (discussionMBMessage.isRoot()) {
462                                    continue;
463                            }
464    
465                            MBMessage importedDiscussionMBMessage =
466                                    MBMessageLocalServiceUtil.fetchMBMessageByUuidAndGroupId(
467                                            discussionMBMessage.getUuid(), group.getGroupId());
468    
469                            Assert.assertNotNull(importedDiscussionMBMessage);
470                    }
471            }
472    
473            protected void validateExport(
474                            PortletDataContext portletDataContext, StagedModel stagedModel,
475                            Map<String, List<StagedModel>> dependentStagedModelsMap)
476                    throws Exception {
477    
478                    Element rootElement = portletDataContext.getExportDataRootElement();
479    
480                    List<Element> stagedModelGroupElements = new ArrayList<Element>();
481    
482                    Class<?> stagedModelClass = getStagedModelClass();
483    
484                    String stagedModelClassSimpleName = stagedModelClass.getSimpleName();
485    
486                    stagedModelGroupElements.addAll(
487                            rootElement.elements(stagedModelClassSimpleName));
488    
489                    for (String dependentStagedModelClassSimpleName :
490                                    dependentStagedModelsMap.keySet()) {
491    
492                            stagedModelGroupElements.addAll(
493                                    rootElement.elements(dependentStagedModelClassSimpleName));
494                    }
495    
496                    for (Element stagedModelGroupElement : stagedModelGroupElements) {
497                            String className = stagedModelGroupElement.getName();
498    
499                            List<StagedModel> dependentStagedModels =
500                                    dependentStagedModelsMap.get(className);
501    
502                            if (dependentStagedModels == null) {
503                                    dependentStagedModels = new ArrayList<StagedModel>();
504                            }
505                            else {
506                                    dependentStagedModels = ListUtil.copy(dependentStagedModels);
507                            }
508    
509                            if (className.equals(stagedModelClassSimpleName)) {
510                                    dependentStagedModels.add(stagedModel);
511                            }
512    
513                            List<Element> elements = stagedModelGroupElement.elements();
514    
515                            Assert.assertEquals(dependentStagedModels.size(), elements.size());
516    
517                            for (Element element : elements) {
518                                    String path = element.attributeValue("path");
519    
520                                    Assert.assertNotNull(path);
521    
522                                    Iterator<StagedModel> iterator =
523                                            dependentStagedModels.iterator();
524    
525                                    while (iterator.hasNext()) {
526                                            StagedModel dependentStagedModel = iterator.next();
527    
528                                            String dependentStagedModelPath =
529                                                    ExportImportPathUtil.getModelPath(dependentStagedModel);
530    
531                                            if (path.equals(dependentStagedModelPath)) {
532                                                    iterator.remove();
533                                            }
534                                    }
535                            }
536    
537                            Assert.assertTrue(
538                                    "There is more than one element exported with the same path",
539                                    dependentStagedModels.isEmpty());
540                    }
541            }
542    
543            protected void validateImport(
544                            Map<String, List<StagedModel>> dependentStagedModelsMap,
545                            Group group)
546                    throws Exception {
547            }
548    
549            protected void validateImport(
550                            StagedModel stagedModel, StagedModelAssets stagedModelAssets,
551                            Map<String, List<StagedModel>> dependentStagedModelsMap,
552                            Group group)
553                    throws Exception {
554    
555                    StagedModel importedStagedModel = getStagedModel(
556                            stagedModel.getUuid(), group);
557    
558                    Assert.assertNotNull(importedStagedModel);
559    
560                    validateAssets(importedStagedModel, stagedModelAssets, group);
561    
562                    validateComments(stagedModel, importedStagedModel, group);
563    
564                    validateImport(dependentStagedModelsMap, group);
565    
566                    validateRatings(stagedModel, importedStagedModel);
567            }
568    
569            protected void validateRatings(
570                            StagedModel stagedModel, StagedModel importedStagedModel)
571                    throws Exception {
572    
573                    List<RatingsEntry> ratingsEntries =
574                            RatingsEntryLocalServiceUtil.getEntries(
575                                    ExportImportClassedModelUtil.getClassName(stagedModel),
576                                    ExportImportClassedModelUtil.getClassPK(stagedModel),
577                                    WorkflowConstants.STATUS_ANY);
578    
579                    List<RatingsEntry> importedRatingsEntries =
580                            RatingsEntryLocalServiceUtil.getEntries(
581                                    ExportImportClassedModelUtil.getClassName(importedStagedModel),
582                                    ExportImportClassedModelUtil.getClassPK(importedStagedModel),
583                                    WorkflowConstants.STATUS_ANY);
584    
585                    Assert.assertEquals(
586                            ratingsEntries.size(), importedRatingsEntries.size());
587    
588                    for (RatingsEntry ratingsEntry : ratingsEntries) {
589                            Iterator<RatingsEntry> iterator = importedRatingsEntries.iterator();
590    
591                            while (iterator.hasNext()) {
592                                    RatingsEntry importedRatingsEntry = iterator.next();
593    
594                                    if (ratingsEntry.getScore() ==
595                                                    importedRatingsEntry.getScore()) {
596    
597                                            iterator.remove();
598    
599                                            break;
600                                    }
601                            }
602                    }
603    
604                    Assert.assertTrue(importedRatingsEntries.isEmpty());
605            }
606    
607            @DeleteAfterTestRun
608            protected Group liveGroup;
609    
610            protected Element missingReferencesElement;
611            protected PortletDataContext portletDataContext;
612            protected Element rootElement;
613    
614            @DeleteAfterTestRun
615            protected Group stagingGroup;
616    
617            protected UserIdStrategy userIdStrategy;
618            protected ZipReader zipReader;
619            protected ZipWriter zipWriter;
620    
621            protected class StagedModelAssets implements Serializable {
622    
623                    public StagedModelAssets(
624                            AssetCategory assetCategory, AssetTag assetTag,
625                            AssetVocabulary assetVocabulary) {
626    
627                            _assetCategory = assetCategory;
628                            _assetTag = assetTag;
629                            _assetVocabulary = assetVocabulary;
630                    }
631    
632                    public AssetCategory getAssetCategory() {
633                            return _assetCategory;
634                    }
635    
636                    public AssetTag getAssetTag() {
637                            return _assetTag;
638                    }
639    
640                    public AssetVocabulary getAssetVocabulary() {
641                            return _assetVocabulary;
642                    }
643    
644                    public void setAssetCategory(AssetCategory assetCategory) {
645                            _assetCategory = assetCategory;
646                    }
647    
648                    public void setAssetTag(AssetTag assetTag) {
649                            _assetTag = assetTag;
650                    }
651    
652                    public void setAssetVocabulary(AssetVocabulary assetVocabulary) {
653                            _assetVocabulary = assetVocabulary;
654                    }
655    
656                    private AssetCategory _assetCategory;
657                    private AssetTag _assetTag;
658                    private AssetVocabulary _assetVocabulary;
659    
660            }
661    
662    }