لینکهای مفید برای شرکت در مسابقه:
در طول مسابقه، میتوانید سؤالات خود را از قسمت «سؤال بپرسید» مطرح کنید.
اخیراً وبسایت شخصی نیما مورد حملات مشکوک قرار گرفته است. او در حال بررسی لاگهای وبسرور سایتش است تا دریابد این حملات از کدام سمت بودهاند، اما برای این کار از یک ویرایشگر متنی ساده استفاده میکند. او میخواهد بتواند روی لاگها فیلتر اعمال کند تا جستوجوی هدفمندی داشته باشد. از شما میخواهیم چنین برنامهای را برای او پیادهسازی کنید.
پروژهی اولیه را از این لینک دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
exceptions
🔗این بسته شامل استثناهای موردنیاز برنامه است. همهی کلاسهای موجود در این بسته از کلاس RuntimeException
ارثبری میکنند.
Log
🔗هر نمونه از این کلاس بیانگر لاگ یک درخواست است. هر لاگ شامل یک یا چند ویژگی است. این کلاس از قبل بهطور کامل پیادهسازی شده و شامل متدهای زیر است:
setProperty(String name, String value)
: این متد با دریافت نام و مقدار یک ویژگی، آن ویژگی را به ویژگیهای لاگ اضافه میکند.getProperty(String name)
: این متد با دریافت نام یک ویژگی، مقدار آن ویژگی را برمیگرداند. در صورتی که ویژگیای با نام واردشده موجود نباشد، یک استثنا از نوع PropertyNotFoundException
پرتاب میشود.LogPropertyTransformerRepository
🔗بعضی از ویژگیهای لاگها (مانند کد وضعیت پاسخ و زمان ارسال درخواست) ماهیت عددی دارند. این کلاس، مجموعهای از Function<String, Long>
را در خود نگهداری میکند تا با استفاده از آنها، بتوان مقدار عددی معادل بعضی از ویژگیهای لاگها را دریافت کرد. این کلاس از قبل بهطور کامل پیادهسازی شده و شامل متدهای زیر است:
addTransformer(String propertyName, Function<String, Long> transformer)
: این متد با دریافت نام یک ویژگی و یک تابع برای تبدیل مقدار رشتهای ویژگی به مقدار عددی، آن تابع را در Map
موجود در کلاس ذخیره میکند.getTransformer(String propertyName)
: این متد با دریافت نام یک ویژگی، تابع مبدل مقدار آن ویژگی به مقدار عددی را برمیگرداند. در صورتی که تابعی برای ویژگی موردنظر تعریف نشده باشد، یک استثنا از نوع TransformerNotFoundException
پرتاب میشود.Condition
🔗هر نمونه از این کلاس، بیانگر یک شرط (ساده یا مرکب) برای فیلتر کردن لاگها است. پراپرتیهای موردنیاز خود را در این کلاس تعریف کرده و متدهای زیر را در آن پیادهسازی کنید:
equal(String propertyName, String value)
را طوری پیادهسازی کنید که با دریافت نام و مقدار یک ویژگی، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل بودن ویژگی با مقدار موردنظر در آن موجود باشد.notEqual(String propertyName, String value)
را طوری پیادهسازی کنید که با دریافت نام و مقدار یک ویژگی، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل نبودن ویژگی با مقدار موردنظر در آن موجود باشد.in(String propertyName, String... values)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و تعدادی مقدار، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل بودن ویژگی با حداقل یکی از مقادیر واردشده در آن موجود باشد.in(String propertyName, String... values)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و تعدادی مقدار، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل نبودن ویژگی با هیچ یک از مقادیر واردشده در آن موجود باشد.lessThan(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط کوچکتر بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.lessOrEqual(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط کوچکتر یا مساوی بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.greaterThan(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط بزرگتر بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.greaterOrEqual(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط بزرگتر یا مساوی بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.and(Condition condition)
را طوری پیادهسازی کنید که با دریافت یک شرط، یک نمونه از کلاس Condition
برگرداند که شرط آن برابر با AND منطقی شرط فعلی و شرط واردشده باشد.or(Condition condition)
را طوری پیادهسازی کنید که با دریافت یک شرط، یک نمونه از کلاس Condition
برگرداند که شرط آن برابر با OR منطقی شرط فعلی و شرط واردشده باشد.not(Condition condition)
را طوری پیادهسازی کنید که با دریافت یک شرط، یک نمونه از کلاس Condition
برگرداند که شرط آن برابر با NOT منطقی شرط فعلی و شرط واردشده باشد.test(Log log)
را طوری پیادهسازی کنید که با دریافت یک لاگ، در صورتی که لاگ در شرایط فعلی صدق کند، مقدار true
و در غیر اینصورت، مقدار false
را برگرداند.نکته: متدهای and
، or
و not
را باید بهگونهای پیادهسازی کنید که نمونههای جدیدی از کلاس Condition
ایجاد شوند. در واقع، نمونههای کلاس Condition
باید immutable باشند.
LogList
🔗این کلاس، یک List
از لاگها را در خود نگهداری میکند.
all
این کلاس را طوری پیادهسازی کنید که یک LogList
شامل یک List
جدید که لاگهای موجود در آبجکت فعلی در آن قرار گرفتهاند ایجاد کرده و برگرداند.where
این کلاس را طوری پیادهسازی کنید که با دریافت یک Condition
، یک LogList
شامل یک List
جدید که لاگهای موجود در آبجکت فعلی در آن قرار گرفتهاند و در شرط واردشده صدق میکنند ایجاد کرده و برگرداند. ترتیب لاگهای موجود در لیست را نباید تغییر دهید.LogParser
🔗وظیفهی این کلاس، پارس کردن رشتهی لاگها است. لاگها یک schema مشخص دارند که در قالب یک رشته به کانستراکتور این کلاس داده میشود. schema شامل تعدادی متغیر نیز هست که با $
آغاز میشوند. مثالی از یک schema:
در اینصورت، لاگهای پارسشده باید شامل ویژگیهای remote_addr
، remote_user
و... باشند.
نمونهای از یک لاگ که طبق فرمت schema بالا است:
parseLog(String line)
این کلاس را طوری پیادهسازی کنید که با دریافت یک رشتهی یکخطی، یک Log
متناظر با لاگ واردشده برگرداند. در صورتی که لاگ واردشده با schema دادهشده مطابقت نداشت، یک استثنا از نوع LineDoesNotMatchException
پرتاب کنید. ترتیب ویژگیهای Log
خروجی باید مطابق ترتیب متغیرهای موجود در schema باشد.parseLogs(String logs)
را طوری پیادهسازی کنید که با دریافت یک رشتهی یک یا چند خطی، یک LogList
متناظر با لاگهای واردشده برگرداند. برای پیادهسازی این متد، از متد parseLog(String line)
استفاده کنید.parseLogs(File file)
را طوری پیادهسازی کنید که با دریافت یک فایل، یک LogList
متناظر با لاگهای موجود در آن برگرداند. برای پیادهسازی این متد، از متد parseLogs(String logs)
استفاده کنید.با اجرای متد main
موجود در کلاس LogParser
:
خروجی باید بهصورت زیر باشد:
نکته: تستهای نمونهی سؤال در کلاس LogParserSampleTest
موجود هستند. با افزودن JUnit به classpath پروژه، میتوانید آنها را اجرا کنید.
پس از پیادهسازی موارد خواستهشده، یک فایل زیپ آپلود کنید که وقتی آن را باز میکنیم، با فایلهای زیر مواجه شویم: